diff -u --recursive --new-file v2.1.36/linux/CREDITS linux/CREDITS
--- v2.1.36/linux/CREDITS	Wed Apr 16 14:14:58 1997
+++ linux/CREDITS	Tue May 13 21:52:27 1997
@@ -149,12 +149,8 @@
 S: Germany
 
 N: Bill Bogstad
-E: bogstad@cs.jhu.edu
-D: Wrote /proc/self patch
-S: Johns Hopkins University
-S: Computer Science Department
-S: Baltimore, Maryland 21218
-S: USA
+E: bogstad@pobox.com
+D: wrote /proc/self hack, minor samba & dosemu patches
 
 N: Axel Boldt
 E: boldt@math.ucsb.edu
@@ -468,7 +464,7 @@
 S: USA
 
 N: Philip Gladstone
-E: philipg@onsett.com
+E: philip@raptor.com
 D: Kernel / timekeeping stuff
 
 N: Michael A. Griffith
diff -u --recursive --new-file v2.1.36/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.1.36/linux/Documentation/00-INDEX	Wed Jan 15 18:46:05 1997
+++ linux/Documentation/00-INDEX	Mon May 12 10:35:37 1997
@@ -26,6 +26,8 @@
 	- plain ASCII listing of all the nodes in /dev/ with major minor #'s
 digiboard.txt
 	- info on the Digiboard PC/X{i,e,eve} multiport boards.
+digiepca.txt
+	- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 exception.txt
 	- how linux v2.1 handles exceptions without verify_area etc.
 ez.txt
diff -u --recursive --new-file v2.1.36/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.36/linux/Documentation/Changes	Wed Apr 23 19:01:13 1997
+++ linux/Documentation/Changes	Mon May 12 20:47:22 1997
@@ -29,7 +29,7 @@
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: April 17, 1997.
+Last updated: May 12, 1997.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -40,16 +40,16 @@
 
 - Kernel modules	 modutils-2.1.34
 - Gnu C 		 2.7.2.1
-- Binutils		 2.7.0.9
+- Binutils		 2.8.0.3
 - Linux C Library	 5.4.23
 - Dynamic Linker (ld.so) 1.8.5
 - Linux C++ Library	 2.7.2.1
 - Procps		 1.01
-- Mount                  2.6e
-- Net-tools              1.32-alpha
+- Mount                  2.6g
+- Net-tools              1.41
 - Loadlin                1.6a
 - Sh-utils               1.16
-- Autofs                 970409
+- Autofs                 0.3.0
 - NFS                    0.4.21
 
 Upgrade notes
@@ -131,6 +131,9 @@
    To run bootpd, you'll need to issue the following command:   echo 1
 >/proc/sys/net/ipv4/ip_boot_agent
 
+   For support for new features like IPv6, upgrade to the latest
+net-tools.
+
 Mount and network file systems
 ==============================
 
@@ -179,8 +182,7 @@
 *************************************************
 
    There are some simple methods useful to know the version of the
-installed programs and libraries.  The SysVinit version display
-requires that you be logged in as root.
+installed programs and libraries.
 
 Binutils: ld -v
 Gnu C: gcc -v or gcc --version
@@ -190,6 +192,7 @@
 Libc++: ls -l /usr/lib/libg++.so.*
 Modutils: insmod -V
 Mount: mount --version
+Net-tools:  hostname -V
 Procps: ps --version
 RPM:  rpm --version
 Sh-utils:  expr --v
@@ -200,12 +203,12 @@
 Binutils
 ========
 
-The 2.7.0.9 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.7.0.9.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.7.0.9.bin.tar.gz
+The 2.8.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.7.0.9
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.7.0.9
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3
 
 Gnu C
 =====
@@ -295,14 +298,14 @@
 Mount
 =====
 
-The 2.6e release:
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6e.tar.gz
+The 2.6g release:
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz
 
 Autofs
 ======
 
-The 970409 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-970409.tar.gz
+The 0.3.0 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz
 
 NFS
 ===
@@ -310,6 +313,13 @@
 The 0.4.21 release:
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
 ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
+
+Net-tools
+=========
+
+The 0.41 release:
+ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
+ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
 
 Other Info
 ==========
diff -u --recursive --new-file v2.1.36/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.36/linux/Documentation/Configure.help	Wed Apr 23 19:01:14 1997
+++ linux/Documentation/Configure.help	Mon May 12 10:35:37 1997
@@ -2072,6 +2072,20 @@
   and read Documentation/modules.txt. The module will be called
   NCR53c406.o.
 
+Tekram DC390W/U/F (T) SCSI support
+CONFIG_SCSI_DC390W
+  This driver supports the Tekram DC390W/U/F (T) PCI SCSI host adapters with
+  the NCR/Symbios 53c825/875 chips. If you have a DC390 (T) adaptor with the 
+  Am53C974A chip use the DC390(T) driver.
+
+Tekram DC390(T) (AMD PCscsi) SCSI support
+CONFIG_SCSI_DC390T
+  This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
+  the Am53C974A chip, and perhaps other cards using the same chip.
+  
+  This driver does _not_ support the DC390W/U/F adaptor with the 
+  NCR/Symbios chips.
+
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
   This is support for the AM53/79C974 SCSI host adapters. Please read
@@ -4036,6 +4050,16 @@
   N here so that they can use the serial port for modem, mouse or some
   other device.
 
+Digi Intl. epca support
+CONFIG_DIGIEPCA
+  This is a driver for Digi Internationals Xx, Xeve, and Xem 
+  series of cards.  This driver supports the original PC (ISA) boards as
+  well as PCI, and EISA.  If you have a card like this, say Y here and read
+  the file Documentation/digiepca.txt.  NOTE: This driver is seperate from
+  the driver written and copyrighted by Troy De Jongh.  Because they both
+  attempt (In some cases) to access the same hardware only one of these
+  drivers (CONFIG_DIGIEPCA or CONFIG_DIGI) should be selected.
+
 Digiboard PC/Xx Support
 CONFIG_DIGI
   This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
@@ -4918,9 +4942,13 @@
 Amiga AutoConfig Identification
 CONFIG_ZORRO
   This enables support for automatic identification of Amiga expansion
-  cards that obey the AutoConfig(tm) specification.  You should say Y
-  to this question unless you have no expansion cards and no intention
-  of getting any.
+  cards that obey the AutoConfig(tm) specification.
+  Say Y if you want your expansion cards to be identified on bootup;
+  it will enlarge your kernel by about 10KB. The identification
+  information is also available through /proc/zorro (say Y to
+  "/proc filesystem support"!).
+  Note that even if you say N here, you can still use your expansion
+  cards. If in doubt, say Y.
 
 Amiga OCS chipset support
 CONFIG_AMIFB_OCS
@@ -4948,6 +4976,8 @@
   Please note that its use is not all that intuitive (i.e. if you have
   any questions, be sure to ask!).  Say N unless you have a Cybervision
   64 or plan to get one before you next recompile the kernel.
+  Please note that this driver DOES NOT support the Cybervision 64 3D
+  card at present, as they use incompatible video chips.
 
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
@@ -5188,6 +5218,16 @@
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+Atari DSP56k Digital Signal Processor support
+CONFIG_ATARI_DSP56K
+  If you want to be able to use the DSP56001 in Falcons, say Y.
+  This driver is still experimental, and if you don't know what it is,
+  or if you don't have this processor, just say N.
+  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.
+
 Amiga builtin serial support
 CONFIG_AMIGA_BUILTIN_SERIAL
   If you want to use your Amiga's built-in serial port in Linux, say
@@ -5317,7 +5357,7 @@
 # LocalWords:  mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io
 # LocalWords:  OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser
 # LocalWords:  setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc
-# LocalWords:  PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu
+# LocalWords:  PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu 
 # LocalWords:  YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc
 # LocalWords:  traduc Bourgin dbourgin helptext menuconfig kfill READMEs HOWTOs
 # LocalWords:  IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti
diff -u --recursive --new-file v2.1.36/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.1.36/linux/Documentation/devices.tex	Sun Apr 13 10:18:20 1997
+++ linux/Documentation/devices.tex	Mon May 12 10:35:37 1997
@@ -15,6 +15,7 @@
 %
 \begin{document}
 \newcommand{\file}{\tt}			% Style to use for a filename
+\newcommand{\url}{\it}		        % Style to use for an URL
 \newcommand{\hex}{\tt}			% Style to use for a hex number
 \newcommand{\ud}{(Under development)}	% Abbreviation
 \newcommand{\1}{\({}^1\)}
@@ -46,7 +47,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: April 7, 1997}
+\date{Last revised: May 1, 1997}
 \maketitle
 %
 \noindent
@@ -60,17 +61,19 @@
 \LaTeX\ version is authoritative.
 
 This document is included by reference into the Linux Filesystem
-Standard (FSSTND).  The FSSTND is available via FTP from
-tsx-11.mit.edu in the directory {\file
-/pub/linux/docs/linux-standards/fsstnd}.
+Standard (FSSTND).  The FSSTND is available from
+{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}.
 
 To have a major number allocated, or a minor number in situations
 where that applies (e.g.\ busmice), please contact me with the
-appropriate device information.  Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note.  When sending me
-mail, {\em please\/} include the word ``device'' in the subject so
-your mail won't accidentally get buried!
+appropriate device information.  I *very* much appreciate if you send
+me a device description in the same format as the ones already in this
+file.  Also, if you have additional information regarding any of the
+devices listed below, or if I have made a mistake, I would greatly
+appreciate a note.
+
+NOTE: When sending me mail, {\em please\/} include the word ``device''
+in the subject so your mail won't accidentally get buried!
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.  Allocations marked (68k/Atari) apply to Linux/68k on
@@ -207,7 +210,9 @@
 \major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
 \major{80}{}{char }{Photometrics AT200 CCD camera}
 \major{81}{}{char }{Brooktree Bt848 frame grabbers}
-\major{82}{--119}{}{Unallocated}
+\major{82}{}{char }{WiNRADiO communications receiver card}
+\major{83}{}{char }{Teletext/videotext interfaces}
+\major{84}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
 \major{128}{--239}{}{Unallocated}
 \major{240}{--254}{}{Local/experimental use}
@@ -1243,7 +1248,7 @@
 \end{devicelist}
 
 \noindent
-See {\em http://www.coda.cs.cmu.edu\/} for information about Coda.
+See {\url http://www.coda.cs.cmu.edu\/} for information about Coda.
 
 \begin{devicelist}
 \major{68}{}{char }{CAPI 2.0 interface}
@@ -1392,7 +1397,28 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{82}{--119}{}{Unallocated}
+\major{82}{}{char }{WiNRADiO communications receiver card}
+	\major{0}{/dev/winradio0}{First WiNRADiO card}
+	\major{1}{/dev/winradio1}{Second WiNRADiO card}
+	\minordots
+\end{devicelist}
+
+\noindent
+The driver and documentation may be obtained from
+{\url http://www.proximity.com.au/~brian/winradio/\/}.
+
+\begin{devicelist}
+\major{83}{}{char }{Teletext/videotext interfaces}
+        \minor{0}{/dev/vtx}{Teletext decoder}
+        \minor{16}{/dev/vttuner}{TV tuner on teletext interface}
+\end{devicelist}
+
+\noindent
+Devices for the driver contained in the VideoteXt package. More information
+on {\url http://home.pages.de/~videotext/\/}.
+
+\begin{devicelist}
+\major{84}{--119}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v2.1.36/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.1.36/linux/Documentation/devices.txt	Sun Apr 13 10:18:20 1997
+++ linux/Documentation/devices.txt	Mon May 12 10:35:37 1997
@@ -1,7 +1,7 @@
 		       LINUX ALLOCATED DEVICES
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		     Last revised: April 7, 1997
+		      Last revised: May 1, 1997
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -18,11 +18,14 @@
 
 To have a major number allocated, or a minor number in situations
 where that applies (e.g. busmice), please contact me with the
-appropriate device information.  Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note.  When sending me
-mail, *please* include the word "device" in the subject so your mail
-won't accidentally get buried!
+appropriate device information.  I *very* much appreciate if you send
+me a device description in the same format as the ones already in this
+file.  Also, if you have additional information regarding any of the
+devices listed below, or if I have made a mistake, I would greatly
+appreciate a note.
+
+NOTE: When sending me mail, *please* include the word "device" in the
+subject so your mail won't accidentally get buried!
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.  Allocations marked (68k/Atari) apply to Linux/68k on
@@ -979,7 +982,22 @@
 		 33 = /dev/bttv-vbi1	VBI data of second Bt848 card
 		      ...
 
- 82-119		UNALLOCATED
+ 82 char	WiNRADiO communications receiver card
+		  0 = /dev/winradio0	First WiNRADiO card
+		  1 = /dev/winradio1	Second WiNRADiO card
+		      ...
+
+		The driver and documentation may be obtained from
+                http://www.proximity.com.au/~brian/winradio/
+
+ 83 char	Teletext/videotext interfaces
+                  0 = /dev/vtx          Teletext decoder
+                 16 = /dev/vttuner      TV tuner on teletext interface
+
+                Devices for the driver contained in the VideoteXt package.
+                More information on http://home.pages.de/~videotext/
+
+ 84-119		UNALLOCATED
 
 120-127		LOCAL/EXPERIMENTAL USE
 
diff -u --recursive --new-file v2.1.36/linux/Documentation/digiepca.txt linux/Documentation/digiepca.txt
--- v2.1.36/linux/Documentation/digiepca.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/digiepca.txt	Mon May 12 10:35:37 1997
@@ -0,0 +1,96 @@
+The Digi Intl. epca driver. 
+----------------------------
+The Digi Intl. epca driver for Linux supports the following boards:
+
+Digi PC/Xem, PC/Xr, PC/Xe, PC/Xi, PC/Xeve 
+Digi EISA/Xem, PCI/Xem, PCI/Xr 
+
+Limitations:
+------------
+Currently the driver only autoprobes for supported PCI boards. 
+
+The Linux MAKEDEV command does not support generating the Digiboard
+Devices.  Users executing digiConfig to setup EISA and PC series cards
+will have their device nodes automaticly constructed (cud?? for ~CLOCAL,
+and ttyD?? for CLOCAL).  Users wishing to boot their board from the LILO
+prompt, or those users booting PCI cards may use buildDIGI to construct 
+the necessary nodes. 
+
+Notes:
+------
+This driver may be configured via LILO.  For users who have already configured
+their driver using digiConfig, configuring from lilo will override previous 
+settings.  Multiple boards may be configured by issuing multiple LILO command 
+lines.  For examples see the bottom of this document.
+
+Device names start at 0 and continue up.  Beware of this as previous Digi 
+drivers started device names with 1.
+
+PCI boards are auto-detected and configured by the driver.  PCI boards will
+be allocated device numbers (internally) begining with the lowest PCI slot
+first.  In other words a PCI card in slot 3 will always have higher device
+nodes than a PCI card in slot 1. 
+
+LILO config examples:
+---------------------
+Using LILO's APPEND command, a string of comma separated identifiers or 
+integers can be used to configure supported boards.  The six values in order 
+are:
+
+   Enable/Disable this card or Override,
+   Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2), 
+                 EISA/Xem (3), PC/64Xe (4), PC/Xi (5), 
+   Enable/Disable alternate pin arrangement,
+   Number of ports on this card,
+   I/O Port where card is configured (in HEX if using string identifiers),
+   Base of memory window (in HEX if using string identifiers), 
+
+NOTE : PCI boards are auto-detected and configured.  Do not attempt to 
+configure PCI boards with the LILO append comand.  If you wish to override
+previous configuration data (As set by digiConfig), but you do not wish to
+configure any specific card (Example if there are PCI cards in the system) 
+the following override command will accomplish this:
+-> append="digi=2"
+
+Samples:
+   append="digiepca=E,PC/Xe,D,16,200,D0000"
+                  or
+   append="digi=1,0,0,16,512,851968"
+
+Supporting Tools:
+-----------------
+Supporting tools include digiDload, digiConfig, buildPCI, and ditty.  See
+/usr/src/linux/Documentation/README.epca.dir/user.doc for more details.  Note,
+this driver REQUIRES that digiDload be executed prior to it being used. 
+Failure to do this will result in an ENODEV error.
+
+The latest version of the tool package is available at:
+ftp://ftp.dgii.com/drivers/linux/released/async/
+
+Documentation:
+--------------
+Complete documentation for this product may be found in the tool package. 
+
+Sources of information and support:
+-----------------------------------
+Digi Intl. support site for this product:
+-> digilnux@dgii.com 
+
+Related information and information concerning other drivers supporting 
+Digi Intl. products:
+
+-> FTP: ftp://dgii.com
+-> Webpage: http://www.dgii.com
+-> Webpage: http://private.fuller.edu/clameter/digi.html
+-> Mailing List: digiboard@list.fuller.edu  Note write e-mail to subscribe
+   common ListServ commands will not work.
+
+Acknowledgments:
+----------------
+Much of this work (And even text) was derived from a similar document 
+supporting the original public domain DigiBoard driver Copyright (C)
+1994,1995 Troy De Jongh.  Many thanks to Christoph Lameter 
+(clameter@fuller.edu) and Mike McLagan (mike.mclagan@linux.org) who authored 
+and contributed to the original document. 
+
+
diff -u --recursive --new-file v2.1.36/linux/Documentation/locks.txt linux/Documentation/locks.txt
--- v2.1.36/linux/Documentation/locks.txt	Thu Oct 10 21:33:33 1996
+++ linux/Documentation/locks.txt	Mon May 12 10:50:31 1997
@@ -2,42 +2,30 @@
 
 		Andy Walker <andy@lysaker.kvaerner.no>
 
-			    21 Sep 1996
+			    12 May 1997
 
 
 1. What's New?
 --------------
 
-1.1 Flock Emulation Warnings
-----------------------------
-Many people will have noticed the ugly messages that the file locking
-code started generating with the release of kernel version 1.3.95. The
-messages look something like this:
-
-    fcntl_setlk() called by process XX with broken flock() emulation
-
-This is a warning for people using older C libraries that those libraries
-are still calling the pre 1.3.x flock() emulation routines, instead of
-the real flock() system call. The old routines are quite badly broken,
-especially with respect to parent-child lock sharing, and can give bad
-results if, for example, sendmail attempts to use them.
-
-Fixed versions of the C libraries have been on public release for many
-months. The latest versions at the time of writing are 5.3.12 (released)
-or 5.4.6 (testing) for ELF. There is also a 4.7.6 release for people
-using a.out systems.
-
-With the release of Linux 2.0 Linus decided to be lenient on the
-stragglers and changed the warning message so that the kernel will only
-complain once and then shut up. That should make life more bearable even
-for people who, for some reason, don't want to upgrade their libraries.
+1.1 Broken Flock Emulation
+--------------------------
 
+The old flock(2) emulation in the kernel was swapped for proper BSD
+compatible flock(2) support in the 1.3.x series of kernels. With the
+release of the 2.1.x kernel series, support for the old emulation has
+been totally removed, so that we don't need to carry this baggage
+forever.
+
+This should not cause problems for anybody, since everybody using a
+2.1.x kernel should have updated their C library to a suitable version
+anyway (see the file "linux/Documentation/Changes".)
 
-1.2 Disallow Mixed Locks
-------------------------
+1.2 Allow Mixed Locks Again
+---------------------------
 
-1.2.1 Sendmail Problems
----------------------
+1.2.1 Typical Problems - Sendmail
+---------------------------------
 Because sendmail was unable to use the old flock() emulation, many sendmail
 installations use fcntl() instead of flock(). This is true of Slackware 3.0
 for example. This gave rise to some other subtle problems if sendmail was
@@ -50,23 +38,17 @@
 
 1.2.2 The Solution
 ------------------
-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.
+The solution I have chosen, after much experimentation and discussion,
+is to make flock() and fcntl() locks oblivious to each other. Both can
+exists, and neither will have any effect on the other.
+
+I wanted the two lock styles to be cooperative, but there were so many
+race and deadlock conditions that the current solution was the only
+practical one. It puts us in the same position as, for example, SunOS
+4.1.x and serveral other commercial Unices. The only OS's that support
+cooperative flock()/fcntl() are those that emulate flock() using
+fcntl(), with all the problems that implies.
+
 
 1.3 Mandatory Locking As A Mount Option
 ---------------------------------------
diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/00-INDEX linux/Documentation/m68k/00-INDEX
--- v2.1.36/linux/Documentation/m68k/00-INDEX	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/m68k/00-INDEX	Mon May 12 10:35:37 1997
@@ -0,0 +1,9 @@
+00-INDEX
+	- this file
+amiboot.txt
+	- info and options for the Linux/m68k Amiga bootstrap (Amiboot)
+framebuffer.txt
+	- info about the Linux/m68k frame buffer device
+kernel-options.txt
+	- command line options for Linux/m68k
+
diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/amiboot.README linux/Documentation/m68k/amiboot.README
--- v2.1.36/linux/Documentation/m68k/amiboot.README	Fri Dec 20 01:19:57 1996
+++ linux/Documentation/m68k/amiboot.README	Wed Dec 31 16:00:00 1969
@@ -1,241 +0,0 @@
-
-		Linux/m68k Amiga Bootstrap version 5.1
-		--------------------------------------
-
-
-0. Introduction
----------------
-
-Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell.
-
-Before you try to boot Linux/m68k for the first time, please read the FAQ
-
-    http://www-agrw.informatik.uni-kl.de/~jmayer/linux68k/linux68k-faq
-
-and the Installation Guide
-
-    http://www.informatik.uni-oldenburg.de/~amigo/inst.html
-
-first. Although the Installation Guide is getting a bit outdated, it's still a
-good starting point.
-
-Amiboot 5.1 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
-interface versions 1.x and 2.x). Please use an older version for older kernels.
-
-
-1. Running Amiboot
-------------------
-
-The Amiboot invocation syntax looks like
-
-    amiboot [options] [kernel command line]
-
-Valid options are:
-
-    --help           Display the usage information
-
-    --kernel file    Use kernel image `file' (default is `vmlinux')
-
-    --ramdisk file   Use ramdisk image `file'.
-
-    --debug          Enable debug mode
-
-    --baud           Set the serial port speed (default is 9600)
-
-    --memfile file   Use memory file `file'
-
-    --keep-video     Don't reset the video mode
-
-    --model id       Set the Amiga model to `id'.
-
-The kernel command line contains the options you want to pass to the kernel and
-to init, the process that's started first by Linux. Please read
-linux/Documentation/m68k/kernel-options.txt for more information.
-
-Normally you only use the --kernel option to specify the file that contains the
-Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file,
-i.e. a file containing a complete file system, instead of from a hard disk
-partition.
-
-Example:
-
-    amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8
-
-Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass
-`root=/dev/hda3 video=font:PEARL8x8' to the kernel.
-
-
-The other options are more specialized. Don't use them unless you really have
-to and you know what you're doing.
-
-The --baud option allows you to specify the serial port speed for initial boot
-information and initial kernel messages. Note: this option does not work with
-kernels with bootinfo interface versions prior to 2.0.
-
-The --memfile option is used to specify the blocks of memory that will be used
-by Linux.
-
-The --keep-video option is necessary if you want to retain the current graphics
-mode (on a graphics board) under Linux. Currently this is only useful if you
-have a CyberVision 64 graphics board.
-
-Finally, --model allows you to specify your Amiga model, and --debug is for
-debugging purposes.
-
-
-2. The memory file
-------------------
-
-If you have some non-AutoConfig memory you want to use under Linux, or if you
-want to disable some parts of your memory (e.g. Zorro II RAM on '040 based
-systems), you have to use a memory file and the --memfile option. This file
-contains information about the memory chunks you want to use under Linux. The
-format for the file is:
-
-    chipramsize
-    [0xfastchunkaddr fastchunksize]
-    [0xfastchunkaddr fastchunksize]
-    ...
-
-For example, if you don't want Linux to use your 2nd meg of chipram, you would
-create a file that looks contains only:
-
-    1048576
-
-If you had 1M of chip ram, 2M of 16 bit FAST ram at address 0x200000 and 16M of
-32 bit FAST ram at address 0x80000000, and you didn't want Linux to use the
-slow 16 bit FAST ram, you'd create a file that looks like:
-
-    1048576
-    0x80000000 16777216
-
-The memory file can also be used to specify in which block of memory the kernel
-will be put. Normally Amiboot will put the kernel in the first block of Fast
-RAM it will find. If you use a memory file, it will put the kernel in the first
-block of fast RAM you specify.
-
-
-3. Amiga models
----------------
-
-If Amiboot incorrectly detects the model of your Amiga, you can force it to
-detect any model you want using the --model option. `id' must be one of the
-numbers as defined in linux/include/asm-m68k/amigahw.h (AMI_*). Currently the
-following models are known:
-
-    Model	    ID
-    -----	    --
-    Amiga 500	     1
-    Amiga 500+	     2
-    Amiga 600	     3
-    Amiga 1000	     4
-    Amiga 1200	     5
-    Amiga 2000	     6
-    Amiga 2500	     7
-    Amiga 3000	     8
-    Amiga 3000T	     9
-    Amiga 3000+	    10
-    Amiga 4000	    11
-    Amiga 4000T	    12
-    CDTV	    13
-    CD32	    14
-    Draco	    15
-
-Note that Amiboot can't distinguish among Amiga models that are very similar to
-each other (e.g. A500/A1000/A2000/A2500 and A3000/A3000T). Of course this is
-harmless and there's no real need to use --model in that case.
-
-Please send me the output of amiboot used with the --debug option if your Amiga
-model is detected incorrectly.
-
-
-4. Abbreviations
-----------------
-
-All options also have a shorthand:
-
-    --help 	    -h
-    --kernel	    -k
-    --ramdisk	    -r
-    --debug	    -d
-    --baud	    -b
-    --memfile	    -m
-    --keep-video    -v
-    --model	    -t
-
-
-5. Miscellaneous
-----------------
-
-Some expansion boards keep on generating interrupts once they were initialized
-under AmigaOS. This can cause an interrupt deadlock while booting Linux. The
-following boards are recognized and disabled:
-
-    o Helfrich Rainbow 3 Graphics Board
-    o Helfrich Piccolo Graphics Board
-    o Helfrich SD64 Graphics Board
-    o Village Tronic Ariadne Ethernet Board
-    o Hydra Systems Amiganet Ethernet Board
-
-The following boards are known to cause problems but we don't have a disable
-routine for them yet:
-
-    o Commodore A2060 Arcnet Card
-    o Ameristar A560 Arcnet Card
-
-If you write a routine to disable an expansion board, please let me know.
-
-
-6. Troubleshooting
-------------------
-
-  - Amiboot says
-
-	This bootstrap is too old/new for this kernel
-
-    This means that you're using a version of Amiboot that's not compatible
-    with the kernel you want to boot.
-
-    Solution: use the correct Amiboot, or use another kernel.
-
-  - Amiboot says
-
-	Warning: too many AutoConfig devices. Ignoring device at 0x????????
-
-    or
-
-	Warning: too many memory blocks. Ignoring block of ???K at 0x????????
-
-    This means that you have more AutoConfig devices or memory chunks than
-    Amiboot supports. Note that you can still boot Linux/m68k, but that the
-    additional devices or memory blocks can't be used.
-
-    Solution: increase the ZORRO_NUM_AUTO (for AutoConfig devices) or
-    NUM_MEMINFO (for memory chunks) values in the kernel sources
-    (linux/include/asm-m68k/zorro.h and linux/include/asm-m68k/setup.h) and
-    recompile both Amiboot and the kernel.
-
-  - If all you get is a grey screen, or if Linux/m68k suddenly locks up during
-    booting, try the following things:
-
-      o Boot with the Startup-Sequence disabled, run SetPatch and try again.
-
-      o If that doesn't work, remove any expansion devices and retry.
-
-      o Look at the characters that are dumped to the serial port during
-	booting.
-
-
-7. Amiga-Lilo
--------------
-
-Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo.
-Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting
-AmigaOS first, and it provides you with a boot menu.
-
-
-8. Credits
-----------
-
-This readme was written by Geert Uytterhoeven. A lot of information was taken
-from the ANNOUNCE-* files by Hamish Macdonald.
diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/amiboot.txt linux/Documentation/m68k/amiboot.txt
--- v2.1.36/linux/Documentation/m68k/amiboot.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/m68k/amiboot.txt	Mon May 12 10:35:37 1997
@@ -0,0 +1,282 @@
+
+		Linux/m68k Amiga Bootstrap version 5.5
+		--------------------------------------
+
+Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Last revised: March 27, 1997
+
+
+0. Introduction
+---------------
+
+Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell.
+
+Before you try to boot Linux/m68k for the first time, please read the FAQ
+
+    http://www.clark.net/pub/lawrencc/linux/faq/faq.html
+
+and the Installation Guide
+
+    http://www.informatik.uni-oldenburg.de/~amigo/inst.html
+
+first. Although the Installation Guide is getting a bit outdated, it's still a
+good starting point.
+
+Amiboot 5.5 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo
+interface versions 1.x and 2.x). Please use an older version for older kernels.
+
+
+1. Running Amiboot
+------------------
+
+The Amiboot invocation syntax looks like
+
+    amiboot [options] [kernel command line]
+
+Basic options:
+
+    --help           Display the usage information
+
+    --kernel file    Use kernel image `file' (default is `vmlinux')
+
+    --ramdisk file   Use ramdisk image `file'
+
+Advanced options:
+
+    --debug          Enable debug mode
+
+    --baud speed     Set the serial port speed (default is 9600 bps)
+
+    --memfile file   Use memory file `file'
+
+    --keep-video     Don't reset the video mode
+
+    --model id       Set the Amiga model to `id'
+
+    --processor cfm  Set the processor type to `cfm'
+
+The kernel command line contains the options you want to pass to the kernel and
+to init, the process that's started first by Linux. Please read
+linux/Documentation/m68k/kernel-options.txt for more information.
+
+Normally you only use the --kernel option to specify the file that contains the
+Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file,
+i.e. a file containing a complete file system, instead of from a hard disk
+partition.
+
+Note that both the kernel image and the ramdisk image can be compressed with
+gzip. Amiboot knows how to deal with gzipped kernel images, and the kernel
+recognizes gzipped ramdisk images.
+
+Example:
+
+    amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8
+
+Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass
+`root=/dev/hda3 video=font:PEARL8x8' to the kernel.
+
+
+The other options are more advanced. Don't use them unless you really have to
+and you know what you're doing.
+
+The --baud option allows you to specify the serial port speed for initial boot
+information and initial kernel messages. Note: this option does not work with
+kernels with bootinfo interface versions prior to 2.0.
+
+The --memfile option is used to specify the blocks of memory that will be used
+by Linux.
+
+The --keep-video option is necessary if you want to retain the current graphics
+mode (on a graphics board) under Linux. Currently this is only useful if you
+have a CyberVision 64 graphics board.
+
+Finally, --model and --processor allow you to specify your Amiga model and
+processor type if they are detected incorrectly, and --debug dumps some
+information which simplifies debugging.
+
+
+2. The memory file
+------------------
+
+If you have some non-AutoConfig memory you want to use under Linux, or if you
+want to disable some parts of your memory (e.g. Zorro II RAM on '040 based
+systems), you have to use a memory file and the --memfile option. This file
+contains information about the memory chunks you want to use under Linux. The
+format for the file is:
+
+    chipramsize
+    [0xfastchunkaddr fastchunksize]
+    [0xfastchunkaddr fastchunksize]
+    ...
+
+For example, if you don't want Linux to use your 2nd meg of chipram, you would
+create a file that contains only:
+
+    1048576
+
+If you had 1M of chip ram, 2M of 16 bit FAST ram at address 0x200000 and 16M of
+32 bit FAST ram at address 0x80000000, and you didn't want Linux to use the
+slow 16 bit FAST ram, you'd create a file that looks like:
+
+    1048576
+    0x80000000 16777216
+
+The memory file can also be used to specify in which block of memory the kernel
+will be put. Normally Amiboot will put the kernel in the first block of Fast
+RAM it will find. If you use a memory file, it will put the kernel in the first
+block of fast RAM you specify.
+
+
+3. Amiga models
+---------------
+
+If Amiboot incorrectly detects the model of your Amiga, you can force it to
+detect any model you want using the --model option. `id' must be one of the
+numbers as defined in linux/include/asm-m68k/amigahw.h (AMI_*). Currently the
+following models are known:
+
+    Model	    ID
+    -----	    --
+    Amiga 500	     1
+    Amiga 500+	     2
+    Amiga 600	     3
+    Amiga 1000	     4
+    Amiga 1200	     5
+    Amiga 2000	     6
+    Amiga 2500	     7
+    Amiga 3000	     8
+    Amiga 3000T	     9
+    Amiga 3000+	    10
+    Amiga 4000	    11
+    Amiga 4000T	    12
+    CDTV	    13
+    CD32	    14
+    Draco	    15
+
+Note that Amiboot can't distinguish among Amiga models that are very similar to
+each other (e.g. A500/A1000/A2000/A2500 and A3000/A3000T). Of course this is
+harmless and there's no real need to use --model in that case.
+
+Please send me the output of amiboot used with the --debug option if your Amiga
+model is detected incorrectly.
+
+
+4. Processor types
+------------------
+
+If your processor is detected incorrectly, you can override this using the
+`--processor cfm' option. `cfm' must be a three-digit number with
+
+  - `c' the CPU (Central Processing Unit) type,
+  - 'f' the FPU (Floating Point Unit) type,
+  - 'm' the MMU (Memory Management Unit) type,
+
+from the table below:
+
+     value |  CPU  |  FPU  |  MMU
+    -------+-------+-------+-------
+       0   |   -   |   -   |   -
+       1   | 68020 | 68881 | 68851
+       2   | 68030 | 68882 | 68030
+       3   | 68040 | 68040 | 68040
+       4   | 68060 | 68060 | 68060
+
+e.g. `444' if you have a 68060 and `303' if you have a 68LC040.
+
+Note that normally you don't have to use this option. It's only needed for some
+combinations of an old Kickstart ROM and a new processor (e.g. a 68060).
+
+
+5. Abbreviations
+----------------
+
+All options also have a shorthand:
+
+    --help 	    -h
+    --kernel	    -k
+    --ramdisk	    -r
+    --debug	    -d
+    --baud	    -b
+    --memfile	    -m
+    --keep-video    -v
+    --model	    -t
+    --processor	    -p
+
+
+6. Miscellaneous
+----------------
+
+Some expansion boards keep on generating interrupts once they were initialized
+under AmigaOS. This can cause an interrupt deadlock while booting Linux. The
+following boards are recognized and disabled:
+
+    o Helfrich Rainbow 3 Graphics Board
+    o Helfrich Piccolo Graphics Board
+    o Helfrich SD64 Graphics Board
+    o Village Tronic Ariadne Ethernet Board
+    o Hydra Systems Amiganet Ethernet Board
+
+The following boards are known to cause problems but we don't have a disable
+routine for them yet:
+
+    o Commodore A2060 Arcnet Card
+    o Ameristar A560 Arcnet Card
+
+If you write a routine to disable an expansion board, please let me know.
+
+
+7. Troubleshooting
+------------------
+
+  - Amiboot says
+
+	This bootstrap is too old/new for this kernel
+
+    This means that you're using a version of Amiboot that's not compatible
+    with the kernel you want to boot.
+
+    Solution: use the correct Amiboot, or use another kernel.
+
+  - Amiboot says
+
+	Warning: too many AutoConfig devices. Ignoring device at 0x????????
+
+    or
+
+	Warning: too many memory blocks. Ignoring block of ???K at 0x????????
+
+    This means that you have more AutoConfig devices or memory chunks than
+    Amiboot supports. Note that you can still boot Linux/m68k, but that the
+    additional devices or memory blocks can't be used.
+
+    Solution: increase the ZORRO_NUM_AUTO (for AutoConfig devices) or
+    NUM_MEMINFO (for memory chunks) values in the kernel sources
+    (linux/include/asm-m68k/zorro.h and linux/include/asm-m68k/setup.h) and
+    recompile both Amiboot and the kernel.
+
+  - If all you get is a grey screen, or if Linux/m68k suddenly locks up during
+    booting, try the following things:
+
+      o Boot with the Startup-Sequence disabled, run SetPatch and try again.
+
+      o If that doesn't work, remove any expansion devices and retry.
+
+      o Check the detected Amiga model and processor type.
+
+      o Look at the characters that are dumped to the serial port during
+	booting.
+
+
+8. Amiga-Lilo
+-------------
+
+Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo.
+Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting
+AmigaOS first, and it provides you with a boot menu.
+
+
+9. Credits
+----------
+
+This readme was written by Geert Uytterhoeven. A lot of information was taken
+from the ANNOUNCE-* files by Hamish Macdonald.
diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/framebuffer.txt linux/Documentation/m68k/framebuffer.txt
--- v2.1.36/linux/Documentation/m68k/framebuffer.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/m68k/framebuffer.txt	Mon May 12 10:35:37 1997
@@ -0,0 +1,370 @@
+
+		The Linux/m68k Frame Buffer Device
+		----------------------------------
+
+Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Last revised: March 23, 1997
+
+
+0. Introduction
+---------------
+
+The frame buffer device provides an abstraction for the graphics hardware. It
+represents the frame buffer of some video hardware and allows application
+software to access the graphics hardware through a well-defined interface, so
+the software doesn't need to know anything about the low-level (hardware
+register) stuff.
+
+The device is accessed through special device nodes, usually located in the
+/dev directory, i.e. /dev/fb*.
+
+
+1. User's View of /dev/fb*
+--------------------------
+
+From the user's point of view, the frame buffer device looks just like any
+other device in /dev. It's a character device using major 29, the minor is
+divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame
+buffers simultaneously) and a resolution code in the lower 5 bits of the minor.
+
+By convention, the following device nodes are used (numbers indicate the device
+minor numbers):
+
+    First frame buffer
+	 0 = /dev/fb0current		Current resolution
+	 1 = /dev/fb0autodetect		Default resolution
+	 2 = /dev/fb0predefined0	Predefined resolutions (22)
+	     ...
+	23 = /dev/fb0predefined21
+	24 = /dev/fb0user0		User defined resolutions (8)
+	     ...
+	31 = /dev/fb0user7                              
+
+    Second frame buffer
+	32 = /dev/fb1current		Current resolution
+	33 = /dev/fb1autodetect		Default resolution
+	34 = /dev/fb1predefined0	Predefined resolutions (22)
+	     ...
+	55 = /dev/fb1predefined21
+	56 = /dev/fb1user0		User defined resolutions (8)
+	     ...                                          
+	63 = /dev/fb1user7                                 
+
+and so on...
+
+The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer
+together with the currently set video parameters; (minor & 31) == 1
+(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor
+stands for some predefined or user defined video mode.
+
+The predefined entries (/dev/fb?predefined*) usually have a device dependent
+name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and
+/dev/fb0ttmid on Atari. These are meant to contain hardware dependent
+resolutions.
+
+The user defined resolutions (/dev/fb?user?) are meant to be filled in by the
+user. This way the user can store his favorite 8 resolutions during boot up.
+
+Note: if you need more than 8 user defined resolutions, you can always override
+the predefined resolutions by storing them in one of the predefined entries.
+But this is not recommended. Similarly, if there are more than 22 predefined
+resolutions, the device writer can decide to store them in the user defined
+entries.
+
+If the device is opened (for writing), the frame buffer driver switches to the
+selected video mode. Thus, you can switch video modes by writing to a frame
+buffer device, e.g.
+
+    > /dev/fb0ttlow
+
+will switch your video to TT low mode. Note: if you specify a resolution which
+contains a value that's not possible on your hardware, the frame buffer device
+will round it up (if possible) or return an error condition.
+
+The frame buffer devices are also `normal' memory devices, this means, you can
+read and write their contents. You can, for example, make a screen snapshot by
+
+  cp /dev/fb0current myfile
+
+There also can be more than one frame buffer at a time, e.g. if you have a
+graphics card in addition to the built-in hardware. The corresponding frame
+buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently.
+
+Application software that uses the frame buffer device (e.g. the X server) will
+use /dev/fb0current by default. You can specify an alternative resolution by
+setting the environment variable $FRAMEBUFFER to the path name of a frame
+buffer device, e.g. (for sh/bash users):
+
+    export FRAMEBUFFER=/dev/fb0multiscan
+
+or (for csh users):
+
+    setenv FRAMEBUFFER /dev/fb0multiscan
+
+After this the X server will use the multiscan video mode.
+
+
+2. Programmer's View of /dev/fb*
+--------------------------------
+
+As you already know, a frame buffer device is a memory device like /dev/mem and
+it has the same features. You can read it, write it, seek to some location in
+it and mmap() it (the main usage). The difference is just that the memory that
+appears in the special file is not the whole memory, but the frame buffer of
+some video hardware.
+
+/dev/fb* also allows several ioctls on it, by which lots of information about
+the hardware can be queried and set. The color map handling works via ioctls,
+too. Look into <linux/fb.h> for more information on what ioctls exist and on
+which data structures they work. Here's just a brief overview:
+
+  - You can request unchangeable information about the hardware, like name,
+    organization of the screen memory (planes, packed pixels, ...) and address
+    and length of the screen memory.
+
+  - You can request and change variable information about the hardware, like
+    visible and virtual geometry, depth, color map format, timing, and so on.
+    If you try to change that informations, the driver maybe will round up some
+    values to meet the hardware's capabilities (or return EINVAL if that isn't
+    possible).
+
+  - You can get and set parts of the color map. Communication is done with 16
+    bit per color part (red, green, blue, transparency) to support all existing
+    hardware. The driver does all the computations needed to bring it into the
+    hardware (round it down to less bits, maybe throw away transparency).
+
+All this hardware abstraction makes the implementation of application programs
+easier and more portable. E.g. the X server works completely on /dev/fb* and
+thus doesn't need to know, for example, how the color registers of the concrete
+hardware are organized. XF68_FBDev is a general X server for bitmapped,
+unaccelerated video hardware. The only thing that has to be built into
+application programs is the screen organization (bitplanes or chunky pixels
+etc.), because it works on the frame buffer image data directly.
+
+For the future it is planned that frame buffer drivers for graphics cards and
+the like can be implemented as kernel modules that are loaded at runtime. Such
+a driver just has to call register_framebuffer() and supply some functions.
+Writing and distributing such drivers independently from the kernel will save
+much trouble...
+
+
+3. Frame Buffer Resolution Maintenance
+--------------------------------------
+
+Frame buffer resolutions are maintained using the utility `fbset'. It allows to
+change the video mode properties of the current or a user defined resolution.
+It's main usage is to tune video modes and to store custom resolutions into one
+of the /dev/fb?user?  entries, e.g. during boot up in one of your /etc/rc.* or
+/etc/init.d/* files, after which those resolutions can be used by applications.
+
+Fbset uses a video mode database stored in a configuration file, so you can
+easily add your own modes and refer to them with a simple identifier. The fbset
+install script also creates the special device nodes for the device dependent
+predefined resolutions.
+
+
+4. The X Server
+---------------
+
+The X server (XF68_FBDev) is the most notable application program for the frame
+buffer device. The current X server is part of the XFree86/XFree68 release 3.2
+package and has 2 modes:
+
+  - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config
+    file contains a
+
+	Modes "default"
+
+    line, the X server will use the scheme discussed above, i.e. it will start
+    up in the resolution determined by /dev/fb0current (or $FRAMEBUFFER, if
+    set). This is the default for the configuration file supplied with XFree68
+    3.2. It's the most simple configuration (and the only possible one if you
+    want to have a broadcast compatible display, e.g. PAL or NTSC), but it has
+    some limitations.
+
+  - Therefore it's also possible to specify resolutions in the /etc/XF86Config
+    file. This allows for on-the-fly resolution switching while retaining the
+    same virtual desktop size. The frame buffer device that's used is still
+    /dev/fb0current (or $FRAMEBUFFER), but the available resolutions are
+    defined by /etc/XF86Config now. The disadvantage is that you have to
+    specify the timings in a different format (but `fbset -x' may help) and
+    that you can't have a broadcast compatible display (e.g. no PAL or NTSC).
+
+To tune a video mode, you can use fbset or xvidtune. Note that xvidtune doesn't
+work 100% with XF68_FBDev: the reported clock values are always incorrect.
+
+There exists also an accelerated X server for the Cybervision 64 graphics
+board, but that's not discussed here.
+
+
+5. Video Mode Timings
+---------------------
+
+A monitor draws an image on the screen by using an electron beam (3 electron
+beams for most color models, 1 electron beam for Trinitron color monitors and
+monochrone monitors). The front of the screen is covered by a pattern of
+colored phospors (pixels). If a phospor is hit by an electron, it emits a
+photon and thus becomes visible.
+
+The electron beam draws horizontal lines (scanlines) from left to right, and
+from the top to the bottom of the screen. By modifying the intensity of the
+electron beam, pixels with various colors and intensities can be shown.
+
+After each scanline the electron beam has to move back to the left side of the
+screen and to the next line: this is called the horizontal retrace. After the
+whole screen (frame) was painted, the beam moves back to the upper left corner:
+this is called the vertical retrace. During both the horizontal and vertical
+retrace, the electron beam is turned off (blanked).
+
+The speed at which the electron beam paints the pixels is determined by the
+dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions
+of cycles per second), each pixel is 35242 ps (picoseconds) long:
+
+    1/(28.37516E6 Hz) = 35.242E-9 s
+
+If the screen resolution is 640x480, it will take
+
+    640*35.242E-9 s = 22.555E-6 s
+
+to paint the 640 (xres) pixels on one scanline. But the horizontal retrace
+also takes time (e.g. 272 `pixels'), so a full scanline takes
+
+    (640+272)*35.242E-9 s = 32.141E-6 s
+
+We'll say that the horizontal scanrate is about 31 kHz:
+
+    1/(32.141E-6 s) = 31.113E3 Hz
+
+A full screen counts 480 (yres) lines, but we have to consider the vertical
+retrace too (e.g. 49 `pixels'). So a full screen will take
+
+    (480+49)*32.141E-6 s = 17.002E-3 s
+
+The vertical scanrate is about 59 Hz:
+
+    1/(17.002E-3 s) = 58.815 Hz
+
+This means the screen data is refreshed about 59 times per second. To have a
+stable picture without visible flicker, VESA recommends a vertical scanrate of
+at least 72 Hz. But the perceived flicker is very human dependent: some people
+can use 50 Hz without any trouble, while I'll notice if it's less than 80 Hz.
+
+Since the monitor doesn't know when a new scanline starts, the graphics board
+will supply a synchronization pulse (horizontal sync or hsync) for each
+scanline.  Similarly it supplies a synchronization pulse (vertical sync or
+vsync) for each new frame. The position of the image on the screen is
+influenced by the moments at which the synchronization pulses occur.
+
+The following picture summarizes all timings. The horizontal retrace time is
+the sum of the left margin, the right margin and the hsync length, while the
+vertical retrace time is the sum of the upper margin, the lower margin and the
+vsync length.
+
+  +----------+---------------------------------------------+----------+-------+
+  |          |                ^                            |          |       |
+  |          |                |upper_margin                |          |       |
+  |          |                ¥                            |          |       |
+  +----------###############################################----------+-------+
+  |          #                ^                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |   left   #                |                            #  right   | hsync |
+  |  margin  #                |       xres                 #  margin  |  len  |
+  |<-------->#<---------------+--------------------------->#<-------->|<----->|
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |yres                        #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                |                            #          |       |
+  |          #                ¥                            #          |       |
+  +----------###############################################----------+-------+
+  |          |                ^                            |          |       |
+  |          |                |lower_margin                |          |       |
+  |          |                ¥                            |          |       |
+  +----------+---------------------------------------------+----------+-------+
+  |          |                ^                            |          |       |
+  |          |                |vsync_len                   |          |       |
+  |          |                ¥                            |          |       |
+  +----------+---------------------------------------------+----------+-------+
+
+The frame buffer device expects all horizontal timings in number of dotclocks
+(in picoseconds, 1E-12 s), and vertical timings in number of scanlines.
+
+
+6. Converting XFree86 timing values info frame buffer device timings
+--------------------------------------------------------------------
+
+An XFree86 mode line consists of the following fields:
+ "800x600"     50      800  856  976 1040    600  637  643  666
+ < name >     DCF       HR  SH1  SH2  HFL     VR  SV1  SV2  VFL
+
+The frame buffer device uses the following fields:
+
+  - pixclock: pixel clock in ps (pico seconds)
+  - left_margin: time from sync to picture
+  - right_margin: time from picture to sync
+  - upper_margin: time from sync to picture
+  - lower_margin: time from picture to sync
+  - hsync_len: length of horizontal sync
+  - vsync_len: length of vertical sync
+
+1) Pixelclock:
+   xfree: in MHz
+   fb: In Picoseconds (ps)
+
+   pixclock = 1000000 / DCF
+
+2) horizontal timings:
+   left_margin = HFL - SH2
+   right_margin = SH1 - HR
+   hsync_len = SH2 - SH1
+
+3) vertical timings:
+   upper_margin = VFL - SV2
+   lower_margin = SV1 - VR
+   vsync_len = SV2 - SV1
+
+Good examples for VESA timings can be found in the XFree86 source tree,
+under "xc/programs/Xserver/hw/xfree86/doc/modeDB.txt".
+
+
+7. References
+-------------
+
+For more specific information about the frame buffer device and its
+applications, please refer to the following documentation:
+
+  - The manual pages for fbset: fbset(8), fb.modes(5)
+  - The manual pages for XFree68: XF68_FBDev(1), XF86Config(4/5)
+  - The mighty kernel sources:
+      o linux/include/linux/fb.h
+      o linux/drivers/char/fbmem.c
+      o linux/arch/m68k/*/*fb.c
+
+
+8. Downloading
+--------------
+
+All necessary files can be found at
+
+    ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/
+
+and on its mirrors.
+
+  
+9. Credits                                                       
+----------                                                       
+                
+This readme was written by Geert Uytterhoeven, partly based on the original
+`X-framebuffer.README' by Roman Hodek and Martin Schaller. Section 6 was
+provided by Frank Neumann.
+
+The frame buffer device abstraction was designed by Martin Schaller.
diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt
--- v2.1.36/linux/Documentation/m68k/kernel-options.txt	Fri Dec 20 01:19:57 1996
+++ linux/Documentation/m68k/kernel-options.txt	Mon May 12 10:35:37 1997
@@ -800,6 +800,18 @@
   No argument. Used to separate blocks of keywords when there's more
 than one host adapter in the system.
 
+5.3.7) nodma
+------------
+
+Syntax: nodma:x
+
+  If x is 1 (or if the option is just written as "nodma"), the WD33c93
+controller will not use DMA (= direct memory access) to access the
+Amiga's memory.  This is useful for some systems (like A3000's and
+A4000's with the A3640 accelerator, revision 3.0) that have problems
+using DMA to chip memory.  The default is 0, i.e. to use DMA if
+possible.
+
 
 5.4) gvp11=
 -----------
diff -u --recursive --new-file v2.1.36/linux/Documentation/networking/net-modules.txt linux/Documentation/networking/net-modules.txt
--- v2.1.36/linux/Documentation/networking/net-modules.txt	Sat Dec 21 03:16:57 1996
+++ linux/Documentation/networking/net-modules.txt	Mon May 12 10:35:37 1997
@@ -109,6 +109,10 @@
 8390.c:
 	(No public options, several other modules need this one)
 
+a2065.c:
+	Since this is a Zorro board, it supports full autoprobing, even for
+	multiple boards. (m68k/Amiga)
+
 ac3200.c:
 	io = 0		(Checks 0x1000 to 0x8fff in 0x1000 intervals)
 	irq = 0		(Read from config register)
@@ -133,11 +137,24 @@
 		       0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370,
 		0x380, 0x390, 0x3A0,			  0x3E0, 0x3F0  )
 
+ariadne.c:
+	Since this is a Zorro board, it supports full autoprobing, even for
+	multiple boards. (m68k/Amiga)
+
 at1700.c:
 	io = 0x260
 	irq = 0
 	(Probes ports: 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300)
 
+atari_bionet.c:
+	Supports full autoprobing. (m68k/Atari)
+
+atari_pamsnet.c:
+	Supports full autoprobing. (m68k/Atari)
+
+atarilance.c:
+	Supports full autoprobing. (m68k/Atari)
+
 atp.c: *Not modularized*
 	(Probes ports: 0x378, 0x278, 0x3BC;
 	 fixed IRQs: 5 and 7			)
@@ -211,6 +228,10 @@
 	(Does EISA-probing, if on EISA-slot;
 	 On ISA-bus probes all ports from 0x100 thru to 0x3E0
 	 in increments of 0x020)
+
+hydra.c:
+	Since this is a Zorro board, it supports full autoprobing, even for
+	multiple boards. (m68k/Amiga)
 
 ibmtr.c:
 	io = 0xa20, 0xa24 (autoprobed by default)
diff -u --recursive --new-file v2.1.36/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt
--- v2.1.36/linux/Documentation/serial-console.txt	Sun Feb  2 05:18:29 1997
+++ linux/Documentation/serial-console.txt	Mon May 12 10:35:37 1997
@@ -47,7 +47,7 @@
    Sysvinit remembers its stty settings in a file in /etc, called
    `/etc/ioctl.save'. REMOVE THIS FILE before using the serial
    console for the first time, because otherwise init will probably
-   set the baudrate to 38400 (bausdrate of the virtual console).
+   set the baudrate to 38400 (baudrate of the virtual console).
 
 5. /dev/console and X
    Programs that want to do something with the virtual console usually
diff -u --recursive --new-file v2.1.36/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.36/linux/MAINTAINERS	Sun Apr 13 10:18:20 1997
+++ linux/MAINTAINERS	Mon May 12 10:35:37 1997
@@ -336,11 +336,12 @@
 W:	http://www-plateau.cs.berkeley.edu/people/chaffee
 S:	Maintained
 
-DIGIBOARD DRIVER:
-P:	Christoph Lameter
-M:	clameter@fuller.edu
-L:	digiboard@list.fuller.edu
-S:	Maintained
+DIGI INTL. EPCA DRIVER:
+P:      Daniel Taylor
+M:      support@dgii.com
+M:      digilnux@dgii.com
+L:      digiboard@list.fuller.edu
+S:      Maintained
 
 RISCOM8 DRIVER:
 P:	Dmitry Gorodchanin
diff -u --recursive --new-file v2.1.36/linux/Makefile linux/Makefile
--- v2.1.36/linux/Makefile	Wed Apr 23 19:01:14 1997
+++ linux/Makefile	Mon May 12 10:35:37 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 36
+SUBLEVEL = 37
 
 ARCH := $(shell uname -m | sed s/i.86/i386/)
 
@@ -352,6 +352,8 @@
 	rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
                 -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
                 -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
+	rm -f drivers/sound/Config.in
+	cp drivers/sound/Config.std drivers/sound/Config.in
 
 backup: mrproper
 	cd .. && tar cf - linux/ | gzip -9 > backup.gz
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.36/linux/arch/alpha/defconfig	Wed Apr 16 14:14:59 1997
+++ linux/arch/alpha/defconfig	Mon May 12 10:35:37 1997
@@ -42,6 +42,13 @@
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_EM86=y
+# CONFIG_PNP_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
 
 #
 # Floppy, IDE, and other block devices
@@ -72,9 +79,10 @@
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
-# CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -133,11 +141,11 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 CONFIG_SCSI_QLOGIC_ISP=y
 # CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
@@ -155,19 +163,22 @@
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
-# CONFIG_LAPBETHER is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
 
 #
 # ISDN subsystem
@@ -192,12 +203,16 @@
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 # CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
@@ -206,12 +221,8 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-# CONFIG_DIGI is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_STALDRV is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_ESPSERIAL is not set
-# CONFIG_PRINTER is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_MOUSE=y
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
@@ -224,7 +235,6 @@
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
-CONFIG_RTC_ARC=y
 
 #
 # Sound
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.36/linux/arch/alpha/kernel/entry.S	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/kernel/entry.S	Mon May 12 10:35:37 1997
@@ -126,7 +126,8 @@
 .ent	entInt
 entInt:
 	SAVE_ALL
-	ldq	$8,current_set
+	lda	$8,0x3fff
+	bic	$30,$8,$8
 	jsr	$26,do_entInt
 	br	$31,ret_from_sys_call
 .end entInt
@@ -147,7 +148,8 @@
 	stq	$15,48($30)
 	addq	$30,56,$19
 /* handle the fault */
-	ldq	$8,current_set
+	lda	$8,0x3fff
+	bic	$30,$8,$8
 	jsr	$26,do_page_fault
 /* reload the registers after the exception code played.  */
 	ldq	$9,0($30)
@@ -167,7 +169,8 @@
 .ent	entArith
 entArith:
 	SAVE_ALL
-	ldq	$8,current_set
+	lda	$8,0x3fff
+	bic	$30,$8,$8
 	/* How much of a win is this clockwise?  We are, after all, messing
 	   up the call/return prefetch stack.  -- rth */
 	lda	$27,do_entArith
@@ -180,7 +183,8 @@
 .ent	entIF
 entIF:
 	SAVE_ALL
-	ldq	$8,current_set
+	lda	$8,0x3fff
+	bic	$30,$8,$8
 	lda	$27,do_entIF
 	lda	$26,ret_from_sys_call
 	jsr	$31,($27),do_entIF
@@ -221,12 +225,13 @@
 .globl	__kernel_thread
 .ent	__kernel_thread
 __kernel_thread:
+	ldgp $29,0($27)		/* we can be called from a module */
 	.frame $30, 4*8, $26
 	subq $30,4*8,$30
 	stq $10,16($30)
 	stq $9,8($30)
 	stq $26,0($30)
-	.prologue 0
+	.prologue 1
 	bis $17,$17,$9		/* save fn */
 	bis $18,$18,$10		/* save arg */
 	bsr $26,kernel_clone
@@ -238,10 +243,9 @@
 	ret $31,($26),1
 /* this is in child: look out as we don't have any stack here.. */
 1:	bis $9,$9,$27		/* get fn */
-	br $29,2f
-2:	ldgp $29,0($29)
+	lda $8,0x3fff
 	bis $10,$10,$16		/* get arg */
-	ldq $8,current_set
+	bic $30,$8,$8		/* get current */
 	jsr $26,($27)
 	bis $0,$0,$16
 	jsr $26,sys_exit
@@ -382,7 +386,8 @@
 	stq $29,232($30)
 	stq $30,240($30)
 	stq $31,248($30)
-	ldq $8,current_set
+	lda $8,0x3fff
+	bic $30,$8,$8
 	jsr $26,do_entUna
 	ldq $0,0($30)
 	ldq $1,8($30)
@@ -432,7 +437,8 @@
 	stq $14,40($30)
 	stq $15,48($30)
 	bis $31,$30,$19
-	ldq $8,current_set
+	lda $8,0x3fff
+	bic $30,$8,$8
 	jsr $26,do_entUnaUser
 	ldq $9,0($30)
 	ldq $10,8($30)
@@ -497,7 +503,8 @@
 .ent	entSys
 entSys:
 	SAVE_ALL
-	ldq	$8,current_set
+	lda	$8,0x3fff
+	bic	$30,$8,$8
 	lda	$4,NR_SYSCALLS($31)
 	stq	$16,SP_OFF+24($30)
 	lda	$5,sys_call_table
@@ -532,7 +539,7 @@
 ret_from_reschedule:
 	lda	$0,need_resched
 	ldl	$2,0($0)
-	lda	$4,init_task
+	lda	$4,init_task_union
 	bne	$2,reschedule
 	xor	$4,$8,$4
 	beq	$4,restore_all
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.1.36/linux/arch/alpha/kernel/head.S	Wed Apr 16 14:14:59 1997
+++ linux/arch/alpha/kernel/head.S	Mon May 12 10:35:37 1997
@@ -23,9 +23,11 @@
 __start:
 	br	$27,1f
 1:	ldgp	$29,0($27)
-	/* We need to get current loaded up with our first task.  */
-	ldq	$8,current_set
-	/* And then we can start the kernel.  */
+	/* We need to get current loaded up with our first task...  */
+	lda	$8,init_task_union
+	/* ... and find our stack ... */
+	lda	$30,0x4000($8)
+	/* ... and then we can start the kernel.  */
 	jsr	$26,start_kernel
 	halt
 	.end __start
@@ -61,22 +63,6 @@
 	call_pal PAL_rdusp
 	ret	($26)
 	.end rdusp
-
-	.align 3
-	.globl	tbi
-	.ent	tbi
-tbi:
-	call_pal PAL_tbi
-	ret	($26)
-	.end tbi
-
-	.align 3
-	.globl	imb
-	.ent	imb
-imb:
-	call_pal PAL_imb
-	ret	($26)
-	.end imb
 
 	.align 3
 	.globl	rdmces
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.1.36/linux/arch/alpha/kernel/process.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/kernel/process.c	Mon May 12 10:35:37 1997
@@ -37,6 +37,24 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+union task_union init_task_union __attribute__((section("init_task")))
+	 = { task: INIT_TASK };
 
 /*
  * No need to acquire the kernel lock, we're entirely local..
@@ -186,7 +204,7 @@
 	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
 	if (!(regs->ps & 8))
 		stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
-	childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+	childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
 		
 	*childregs = *regs;
 	childregs->r0 = 0;
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.36/linux/arch/alpha/kernel/ptrace.c	Sun Jan 26 03:40:45 1997
+++ linux/arch/alpha/kernel/ptrace.c	Mon May 12 10:35:37 1997
@@ -67,7 +67,7 @@
  *  |				     |			      |
  *  |				     |			      v
  *  +================================+ <-------------------------
- *					task->kernel_stack_page
+ *					task + PAGE_SIZE
  */
 #define PT_REG(reg)	(PAGE_SIZE - sizeof(struct pt_regs)	\
 			 + (long)&((struct pt_regs *)0)->reg)
@@ -107,19 +107,6 @@
 
 static long zero;
 
-
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * Get contents of register REGNO in task TASK.
  */
@@ -133,7 +120,7 @@
 		zero = 0;
 		addr = &zero;
 	} else {
-		addr = (long *) (task->kernel_stack_page + regoff[regno]);
+		addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
 	}
 	return *addr;
 }
@@ -150,7 +137,7 @@
 	} else if (regno == 31) {
 		addr = &zero;
 	} else {
-		addr = (long *) (task->kernel_stack_page + regoff[regno]);
+		addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
 	}
 	*addr = data;
 	return 0;
@@ -507,7 +494,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		goto out;
 	if (request == PTRACE_ATTACH) {
 		ret = -EPERM;
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.1.36/linux/arch/alpha/kernel/setup.c	Wed Apr 16 14:14:59 1997
+++ linux/arch/alpha/kernel/setup.c	Mon May 12 10:35:37 1997
@@ -21,9 +21,9 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/config.h>	/* CONFIG_ALPHA_LCA etc */
+#include <linux/ioport.h>
 
 #ifdef CONFIG_RTC
-#include <linux/ioport.h>
 #include <linux/timex.h>
 #endif
 
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.1.36/linux/arch/alpha/mm/init.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/mm/init.c	Mon May 12 10:35:37 1997
@@ -133,7 +133,6 @@
 	init_task.tss.ptbr = newptbr;
 	init_task.tss.pal_flags = 1;	/* set FEN, clear everything else */
 	init_task.tss.flags = 0;
-	init_task.kernel_stack_page = INIT_STACK;
 	load_PCB(&init_task.tss);
 
 	flush_tlb_all();
@@ -182,7 +181,7 @@
                 atomic_set(&mem_map[MAP_NR(addr)].count, 1);
                 free_page(addr);
         }
-        printk ("Freeing unused kernel memory: %dk freed\n",
+        printk ("Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
 
diff -u --recursive --new-file v2.1.36/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds
--- v2.1.36/linux/arch/alpha/vmlinux.lds	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/vmlinux.lds	Mon May 12 10:35:37 1997
@@ -5,6 +5,7 @@
    . = 0xfffffc0000310000;
    _text = .;
    .text : { *(.text) }
+   .text2 : { *(.text2) }
    _etext = .;
 
   /* Exception table */
@@ -25,8 +26,11 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(8192);
+  . = ALIGN(2*8192);	/* Align double page for init_task_union */
   __init_end = .;
+
+  /* The initial task and kernel stack */
+  init_task : { *(init_task) }
 
   /* Global data */
   _data = .;
diff -u --recursive --new-file v2.1.36/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.1.36/linux/arch/i386/Makefile	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/Makefile	Mon May 12 10:35:37 1997
@@ -45,7 +45,7 @@
 CFLAGS := $(CFLAGS) -D__SMP__
 endif
 
-HEAD := arch/i386/kernel/head.o
+HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
 CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES)
@@ -85,7 +85,7 @@
 	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
 
 install: vmlinux
-	@$(MAKEBOOT) install
+	@$(MAKEBOOT) BOOTIMAGE=zImage install
 
 archclean:
 	@$(MAKEBOOT) clean
diff -u --recursive --new-file v2.1.36/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.36/linux/arch/i386/defconfig	Mon Apr 14 16:28:06 1997
+++ linux/arch/i386/defconfig	Mon May 12 10:53:01 1997
@@ -141,6 +141,7 @@
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.1.36/linux/arch/i386/kernel/Makefile	Sun Jan 26 02:07:04 1997
+++ linux/arch/i386/kernel/Makefile	Mon May 12 10:35:37 1997
@@ -15,7 +15,7 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 endif
 
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.36/linux/arch/i386/kernel/bios32.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/bios32.c	Mon May 12 10:35:37 1997
@@ -52,6 +52,9 @@
  * Feb 3, 1997  : Set internal functions to static, save/restore flags
  *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
  *
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ *	(mj@atrey.karlin.mff.cuni.cz)
+ *
  */
 
 #include <linux/config.h>
@@ -173,10 +176,10 @@
 		case 0:
 			return address + entry;
 		case 0x80:	/* Not present */
-			printk("bios32_service(%ld) : not present\n", service);
+			printk("bios32_service(0x%lx) : not present\n", service);
 			return 0;
 		default: /* Shouldn't happen */
-			printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n",
+			printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
 				service, return_code);
 			return 0;
 	}
@@ -189,7 +192,7 @@
 } pci_indirect = { 0, KERNEL_CS };
 
 
-__initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static int check_pcibios(void))
 {
 	unsigned long signature;
 	unsigned char present_status;
@@ -212,7 +215,7 @@
 			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
 			  "D" (&pci_indirect)
 			: "bx", "cx");
-	restore_flags(flags);
+		restore_flags(flags);
 
 		present_status = (pack >> 16) & 0xff;
 		major_revision = (pack >> 8) & 0xff;
@@ -232,9 +235,10 @@
 		if (pcibios_entry) {
 			printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
 				major_revision, minor_revision, pcibios_entry);
+			return 1;
 		}
 	}
-	return memory_start;
+	return 0;
 }
 
 
@@ -912,13 +916,11 @@
 				bios32_entry = check->fields.entry;
 				printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
 				bios32_indirect.address = bios32_entry + PAGE_OFFSET;
- 				access_pci = &pci_bios_access;
 			}
 		}
 	}
-	if (bios32_entry) {
-		memory_start = check_pcibios (memory_start, memory_end);
-	}
+	if (bios32_entry && check_pcibios())
+ 		access_pci = &pci_bios_access;
 #endif
 	return memory_start;
 }
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.36/linux/arch/i386/kernel/entry.S	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/entry.S	Mon May 12 10:35:37 1997
@@ -110,62 +110,45 @@
 	addl $4,%esp; \
 	iret
 
-#ifdef	__SMP__
-/* Get the processor ID multiplied by 4 */
-#define GET_PROCESSOR_OFFSET(reg) \
-	movl SYMBOL_NAME(apic_reg), reg; \
-	movl 32(reg), reg; \
-	shrl $22, reg; \
-	andl $0x3C, reg;
-
-#define GET_CURRENT(reg) \
-	GET_PROCESSOR_OFFSET(reg) \
-	movl SYMBOL_NAME(current_set)(reg),reg
-
-#else
-
 #define GET_CURRENT(reg) \
-	movl SYMBOL_NAME(current_set),reg
-
-#endif
+	movl %esp, reg; \
+	andl $-8192, reg;
 
 ENTRY(lcall7)
 	pushfl			# We get a different stack layout with call gates,
 	pushl %eax		# which has to be cleaned up later..
 	SAVE_ALL
-	GET_CURRENT(%ebx)
 	movl EIP(%esp),%eax	# due to call gates, this is eflags, not eip..
 	movl CS(%esp),%edx	# this is eip..
 	movl EFLAGS(%esp),%ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
-	movl %esp,%eax
-	GET_CURRENT(%edx)
-	pushl %eax
-	movl exec_domain(%edx),%edx	# Get the execution domain
+	movl %esp,%ebx
+	pushl %ebx
+	andl $-8192,%ebx	# GET_CURRENT
+	movl exec_domain(%ebx),%edx	# Get the execution domain
 	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
 	call *%edx
 	popl %eax
 	jmp ret_from_sys_call
 
+
 #ifdef __SMP__
 	ALIGN
 	.globl	ret_from_smpfork
 ret_from_smpfork:
+	GET_CURRENT(%ebx)
 	btrl	$0, SYMBOL_NAME(scheduler_lock)
 	jmp	ret_from_sys_call
 #endif /* __SMP__ */
 
-	ALIGN
-handle_bottom_half:
-	pushl $2f
-	jmp SYMBOL_NAME(do_bottom_half)
-
-	ALIGN
-reschedule:
-	pushl $ret_from_sys_call
-	jmp SYMBOL_NAME(schedule)    # test
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
 
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
@@ -180,16 +163,11 @@
 	ALIGN
 	.globl ret_from_sys_call
 	.globl ret_from_intr
-ret_from_intr:
 ret_from_sys_call:
-	GET_CURRENT(%ebx)
 	movl SYMBOL_NAME(bh_mask),%eax
 	andl SYMBOL_NAME(bh_active),%eax
 	jne handle_bottom_half
-2:	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
-	movb CS(%esp),%al
-	testl $(VM_MASK | 3),%eax	# return to VM86 mode or non-supervisor?
-	je 1f
+ret_with_reschedule:
 	cmpl $0,SYMBOL_NAME(need_resched)
 	jne reschedule
 	movl blocked(%ebx),%eax
@@ -197,7 +175,6 @@
 	notl %eax
 	andl signal(%ebx),%eax
 	jne signal_return
-1:	
 	RESTORE_ALL
 	ALIGN
 signal_return:
@@ -230,6 +207,30 @@
 	movl $-ENOSYS,EAX(%esp)
 	jmp ret_from_sys_call
 
+	ALIGN
+ret_from_exception:
+	movl SYMBOL_NAME(bh_mask),%eax
+	andl SYMBOL_NAME(bh_active),%eax
+	jne handle_bottom_half
+	ALIGN
+ret_from_intr:
+	GET_CURRENT(%ebx)
+	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
+	movb CS(%esp),%al
+	testl $(VM_MASK | 3),%eax	# return to VM86 mode or non-supervisor?
+	jne ret_with_reschedule
+	RESTORE_ALL
+
+	ALIGN
+handle_bottom_half:
+	pushl $ret_from_intr
+	jmp SYMBOL_NAME(do_bottom_half)
+
+	ALIGN
+reschedule:
+	pushl $ret_from_sys_call
+	jmp SYMBOL_NAME(schedule)    # test
+
 
 ENTRY(divide_error)
 	pushl $0		# no error code
@@ -260,7 +261,7 @@
 	GET_CURRENT(%ebx)
 	call *%ecx
 	addl $8,%esp
-	jmp ret_from_sys_call
+	jmp ret_from_exception
 
 ENTRY(coprocessor_error)
 	pushl $0
@@ -271,7 +272,7 @@
 	pushl $-1		# mark this as an int
 	SAVE_ALL
 	GET_CURRENT(%ebx)
-	pushl $ret_from_sys_call
+	pushl $ret_from_exception
 	movl %cr0,%eax
 	testl $0x4,%eax			# EM (math emulation bit)
 	je SYMBOL_NAME(math_state_restore)
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.36/linux/arch/i386/kernel/head.S	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/head.S	Mon May 12 10:35:37 1997
@@ -39,19 +39,21 @@
 	jz 1f
 /*
  *	New page tables may be in 4Mbyte page mode and may
- *	be using the global pages.
+ *	be using the global pages. 
+ *
+ *	NOTE! We have to correct for the fact that we're
+ *	not yet offset 0xC0000000..
  */
+#define cr4_bits mmu_cr4_features-0xC0000000
 #ifdef GAS_KNOWS_CR4
 	movl %cr4,%eax		# Turn on 4Mb pages
-	orl $16+128,%eax
+	orl cr4_bits,%eax
 	movl %eax,%cr4
 #else
 	.byte 0x0f,0x20,0xe0
-	orl $16+128,%eax
+	orl cr4_bits,%eax
 	.byte 0x0f,0x22,0xe0
 #endif
-	movl %eax,%cr3		/* flush TLB as per app note */
-	movl %cr0,%eax
 #endif
 /*
  * Setup paging (the tables are already set up, just switch them on)
@@ -67,24 +69,16 @@
 	movl $1f,%eax
 	jmp *%eax		/* make sure eip is relocated */
 1:
+	/* Set up the stack pointer */
+	lss stack_start,%esp
 
 #ifdef __SMP__
 	orw  %bx,%bx
 	jz  1f				/* Initial CPU cleans BSS */
-/*
- *	Set up the stack
- */
-        movl $(KERNEL_DS),%eax         /* walken modif */
-	mov %ax,%ss
-	xorl %eax,%eax
-	movw %cx, %ax
-	movl %eax,%esp
-	addl $0xC0000000, %esp		/* shift it to the upper mapping */
 	pushl $0
 	popfl
 	jmp checkCPUtype
 1:
-	lss stack_start,%esp
 #endif __SMP__
 /*
  * Clear BSS first so that there are no surprises...
@@ -305,15 +299,53 @@
 	jne rp_sidt
 	ret
 
+ENTRY(stack_start)
+	.long SYMBOL_NAME(init_task_union)+8192
+	.long KERNEL_DS
+
+/* This is the default interrupt "handler" :-) */
+int_msg:
+	.asciz "Unknown interrupt\n"
+	ALIGN
+ignore_int:
+	cld
+	pushl %eax
+	pushl %ecx
+	pushl %edx
+	push %ds
+	movl $(KERNEL_DS),%eax
+	mov %ax,%ds
+	mov %ax,%es
+	mov %ax,%fs
+	pushl $int_msg
+	call SYMBOL_NAME(printk)
+	popl %eax
+	pop %ds
+	popl %edx
+	popl %ecx
+	popl %eax
+	iret
+
+/*
+ * The interrupt descriptor table has room for 256 idt's
+ */
+	ALIGN
+.word 0
+idt_descr:
+	.word 256*8-1		# idt contains 256 entries
+	.long SYMBOL_NAME(idt)
+
+	ALIGN
+.word 0
+gdt_descr:
+#ifdef CONFIG_APM
+	.word (11+2*NR_TASKS)*8-1
+#else
+	.word (8+2*NR_TASKS)*8-1
+#endif
+	.long SYMBOL_NAME(gdt)
 
 /*
- * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x101000
- * with the introduction of the compressed boot code.  Theoretically,
- * the original design of overlaying the startup code with the swapper
- * page directory is still possible --- it would reduce the size of the kernel
- * by 2-3k.  This would be a good thing to do at some point.....
- *
  * This is initialized to create a identity-mapping at 0-4M (for bootup
  * purposes) and another mapping of the 0-4M area at virtual address
  * 0xC0000000.
@@ -471,63 +503,29 @@
 ENTRY(empty_zero_page)
 
 .org 0x6000
-
-stack_start:
-	.long SYMBOL_NAME(init_user_stack)+4096
-	.long KERNEL_DS
-
-/* This is the default interrupt "handler" :-) */
-int_msg:
-	.asciz "Unknown interrupt\n"
-	ALIGN
-ignore_int:
-	cld
-	pushl %eax
-	pushl %ecx
-	pushl %edx
-	push %ds
-	push %es
-	push %fs
-	movl $(KERNEL_DS),%eax
-	mov %ax,%ds
-	mov %ax,%es
-	mov %ax,%fs
-	pushl $int_msg
-	call SYMBOL_NAME(printk)
-	popl %eax
-	pop %fs
-	pop %es
-	pop %ds
-	popl %edx
-	popl %ecx
-	popl %eax
-	iret
+ENTRY(this_must_match_init_task)
 
 /*
- * The interrupt descriptor table has room for 256 idt's
+ * This starts the data section. Note that the above is all
+ * in the text section because it has alignment requirements
+ * that we cannot fulfill any other way.
  */
-	ALIGN
-.word 0
-idt_descr:
-	.word 256*8-1		# idt contains 256 entries
-	.long SYMBOL_NAME(idt)
+.data
 
+ALIGN
+/* 256 quadwords - 2048 bytes of idt */
 ENTRY(idt)
 	.fill 256,8,0		# idt is uninitialized
 
-	ALIGN
-.word 0
-gdt_descr:
-#ifdef CONFIG_APM
-	.word (11+2*NR_TASKS)*8-1
-#else
-	.word (8+2*NR_TASKS)*8-1
-#endif
-	.long SYMBOL_NAME(gdt)
-
 /*
  * This gdt setup gives the kernel a 1GB address space at virtual
  * address 0xC0000000 - space enough for expansion, I hope.
+ *
+ * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
+ * gdt entries.  Ugh. 
+ *
+ * NOTE! Make sure the gdt descriptor in head.S matches this if you
+ * change anything.
  */
 ENTRY(gdt)
 	.quad 0x0000000000000000	/* NULL descriptor */
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.36/linux/arch/i386/kernel/i386_ksyms.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon May 12 10:35:37 1997
@@ -39,12 +39,13 @@
 #ifdef __SMP__
 EXPORT_SYMBOL(apic_reg);	/* Needed internally for the I386 inlines */
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(active_kernel_processor);
+EXPORT_SYMBOL_NOVERS(kernel_flag);
+EXPORT_SYMBOL_NOVERS(active_kernel_processor);
 EXPORT_SYMBOL(smp_invalidate_needed);
 EXPORT_SYMBOL_NOVERS(__lock_kernel);
 
 /* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.1.36/linux/arch/i386/kernel/init_task.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/init_task.c	Mon May 12 10:35:37 1997
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.36/linux/arch/i386/kernel/irq.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/irq.c	Mon May 12 10:35:37 1997
@@ -44,9 +44,6 @@
 
 #define CR0_NE 32
 
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
-
 unsigned int local_irq_count[NR_CPUS];
 #ifdef __SMP__
 atomic_t __intel_bh_counter;
@@ -58,51 +55,84 @@
 static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
 #endif
 
-static inline void mask_irq(unsigned int irq_nr)
-{
-	unsigned char mask;
+/*
+ * This contains the irq mask for both irq controllers
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21	(((char *)(&cached_irq_mask))[0])
+#define cached_A1	(((char *)(&cached_irq_mask))[1])
 
-	mask = 1 << (irq_nr & 7);
-	if (irq_nr < 8) {
-		cache_21 |= mask;
-		outb(cache_21,0x21);
+spinlock_t irq_controller_lock;
+
+/*
+ * This is always called from an interrupt context
+ * with local interrupts disabled. Don't worry about
+ * irq-safe locks.
+ *
+ * Note that we always ack the primary irq controller,
+ * even if the interrupt came from the secondary, as
+ * the primary will still have routed it. Oh, the joys
+ * of PC hardware.
+ */
+static inline void mask_and_ack_irq(int irq_nr)
+{
+	spin_lock(&irq_controller_lock);
+	cached_irq_mask |= 1 << irq_nr;
+	if (irq_nr & 8) {
+		inb(0xA1);	/* DUMMY */
+		outb(cached_A1,0xA1);
+		outb(0x20,0xA0);
 	} else {
-		cache_A1 |= mask;
-		outb(cache_A1,0xA1);
+		inb(0x21);	/* DUMMY */
+		outb(cached_21,0x21);
 	}
+	outb(0x20,0x20);
+	spin_unlock(&irq_controller_lock);
 }
 
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void set_irq_mask(int irq_nr)
 {
-	unsigned char mask;
-
-	mask = ~(1 << (irq_nr & 7));
-	if (irq_nr < 8) {
-		cache_21 &= mask;
-		outb(cache_21,0x21);
+	if (irq_nr & 8) {
+		outb(cached_A1,0xA1);
 	} else {
-		cache_A1 &= mask;
-		outb(cache_A1,0xA1);
+		outb(cached_21,0x21);
 	}
 }
 
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+	cached_irq_mask |= 1 << irq_nr;
+	set_irq_mask(irq_nr);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+	cached_irq_mask &= ~(1 << irq_nr);
+	set_irq_mask(irq_nr);
+}
+
 void disable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&irq_controller_lock, flags);
 	mask_irq(irq_nr);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	synchronize_irq();
 }
 
 void enable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
-	save_flags(flags);
-	cli();
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
 	unmask_irq(irq_nr);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 /*
@@ -133,7 +163,8 @@
 #error make irq stub building NR_IRQS dependent and remove me.
 #endif
 
-BUILD_TIMER_IRQ(FIRST,0,0x01)
+BUILD_COMMON_IRQ()
+BUILD_IRQ(FIRST,0,0x01)
 BUILD_IRQ(FIRST,1,0x02)
 BUILD_IRQ(FIRST,2,0x04)
 BUILD_IRQ(FIRST,3,0x08)
@@ -157,10 +188,6 @@
 BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt)
 #endif
 
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
 static void (*interrupt[17])(void) = {
 	IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
 	IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
@@ -168,28 +195,6 @@
 	IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt	
 };
 
-static void (*fast_interrupt[16])(void) = {
-	fast_IRQ0_interrupt, fast_IRQ1_interrupt,
-	fast_IRQ2_interrupt, fast_IRQ3_interrupt,
-	fast_IRQ4_interrupt, fast_IRQ5_interrupt,
-	fast_IRQ6_interrupt, fast_IRQ7_interrupt,
-	fast_IRQ8_interrupt, fast_IRQ9_interrupt,
-	fast_IRQ10_interrupt, fast_IRQ11_interrupt,
-	fast_IRQ12_interrupt, fast_IRQ13_interrupt,
-	fast_IRQ14_interrupt, fast_IRQ15_interrupt
-};
-
-static void (*bad_interrupt[16])(void) = {
-	bad_IRQ0_interrupt, bad_IRQ1_interrupt,
-	bad_IRQ2_interrupt, bad_IRQ3_interrupt,
-	bad_IRQ4_interrupt, bad_IRQ5_interrupt,
-	bad_IRQ6_interrupt, bad_IRQ7_interrupt,
-	bad_IRQ8_interrupt, bad_IRQ9_interrupt,
-	bad_IRQ10_interrupt, bad_IRQ11_interrupt,
-	bad_IRQ12_interrupt, bad_IRQ13_interrupt,
-	bad_IRQ14_interrupt, bad_IRQ15_interrupt
-};
-
 /*
  * Initial irq handlers.
  */
@@ -240,14 +245,10 @@
 		action = irq_action[i];
 		if (!action) 
 			continue;
-		len += sprintf(buf+len, "%2d: %10u %c %s",
-			i, kstat.interrupts[i],
-			(action->flags & SA_INTERRUPT) ? '+' : ' ',
-			action->name);
+		len += sprintf(buf+len, "%2d: %10u   %s",
+			i, kstat.interrupts[i], action->name);
 		for (action=action->next; action; action = action->next) {
-			len += sprintf(buf+len, ",%s %s",
-				(action->flags & SA_INTERRUPT) ? " +" : "",
-				action->name);
+			len += sprintf(buf+len, ", %s", action->name);
 		}
 		len += sprintf(buf+len, "\n");
 	}
@@ -298,13 +299,9 @@
 		for (j=0;j<smp_num_cpus;j++)
 			len+=sprintf(buf+len, "%10d ",
 				int_count[cpu_logical_map[j]][i]);
-		len += sprintf(buf+len, "%c %s",
-			(action->flags & SA_INTERRUPT) ? '+' : ' ',
-			action->name);
+		len += sprintf(buf+len, "  %s", action->name);
 		for (action=action->next; action; action = action->next) {
-			len += sprintf(buf+len, ",%s %s",
-				(action->flags & SA_INTERRUPT) ? " +" : "",
-				action->name);
+			len += sprintf(buf+len, ", %s", action->name);
 		}
 		len += sprintf(buf+len, "\n");
 	}
@@ -393,16 +390,8 @@
 
 static unsigned long previous_irqholder;
 
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
-
 static inline void wait_on_irq(int cpu, unsigned long where)
 {
-	int stuck = INIT_STUCK;
 	int local_count = local_irq_count[cpu];
 
 	/* Are we the only one in an interrupt context? */
@@ -421,13 +410,12 @@
 		 * their things before trying to get the lock again.
 		 */
 		for (;;) {
-			STUCK;
 			check_smp_invalidate(cpu);
 			if (atomic_read(&global_irq_count))
 				continue;
 			if (global_irq_lock)
 				continue;
-			if (!set_bit(0,&global_irq_lock))
+			if (!test_and_set_bit(0,&global_irq_lock))
 				break;
 		}
 		atomic_add(local_count, &global_irq_count);
@@ -456,28 +444,18 @@
 	}
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
 static inline void get_irqlock(int cpu, unsigned long where)
 {
-	int stuck = INIT_STUCK;
-
-	if (set_bit(0,&global_irq_lock)) {
+	if (test_and_set_bit(0,&global_irq_lock)) {
 		/* do we already hold the lock? */
 		if ((unsigned char) cpu == global_irq_holder)
 			return;
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		do {
 			do {
-				STUCK;
 				check_smp_invalidate(cpu);
 			} while (test_bit(0,&global_irq_lock));
-		} while (set_bit(0,&global_irq_lock));		
+		} while (test_and_set_bit(0,&global_irq_lock));		
 	}
 	/*
 	 * Ok, we got the lock bit.
@@ -519,7 +497,8 @@
 {
 	switch (flags) {
 	case 0:
-		__global_sti();
+		release_irqlock(smp_processor_id());
+		__sti();
 		break;
 	case 1:
 		__global_cli();
@@ -533,56 +512,58 @@
 #endif
 
 /*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
  */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(struct pt_regs regs)
 {
+	int irq = regs.orig_eax & 0xff;
 	struct irqaction * action;
-	int do_random, cpu = smp_processor_id();
+	int status, cpu;
+
+	/* 
+	 * mask and ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 */
+	mask_and_ack_irq(irq);
 
+	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
 	kstat.interrupts[irq]++;
 
-	/* slow interrupts run with interrupts enabled */
-	__sti();
+	/* Return with this interrupt masked if no action */
+	status = 0;
 	action = *(irq + irq_action);
-	do_random = 0;
-	while (action) {
-		do_random |= action->flags;
-		action->handler(irq, action->dev_id, regs);
-		action = action->next;
-	}
-	if (do_random & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-	irq_exit(cpu, irq);
-}
-
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
-	struct irqaction * action;
-	int do_random, cpu = smp_processor_id();
+	if (action) {
+		do {
+			status |= action->flags;
+			action->handler(irq, action->dev_id, &regs);
+			action = action->next;
+		} while (action);
+		if (status & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
 
-	irq_enter(cpu, irq);
-	kstat.interrupts[irq]++;
-	action = *(irq + irq_action);
-	do_random = 0;
-	while (action) {
-		do_random |= action->flags;
-		action->handler(irq, action->dev_id, NULL);
-		action = action->next;
+		__cli();
+		spin_lock(&irq_controller_lock);
+		unmask_irq(irq);
+		spin_unlock(&irq_controller_lock);
 	}
-	if (do_random & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
+
 	irq_exit(cpu, irq);
+	/*
+	 * This should be conditional: we should really get
+	 * a return code from the irq handler to tell us
+	 * whether the handler wants us to do software bottom
+	 * half handling or not..
+	 */
+	if (1) {
+		if (bh_active & bh_mask)
+			do_bottom_half();
+	}
 }
 
 int setup_x86_irq(int irq, struct irqaction * new)
@@ -597,10 +578,6 @@
 		if (!(old->flags & new->flags & SA_SHIRQ))
 			return -EBUSY;
 
-		/* Can't share interrupts unless both are same type */
-		if ((old->flags ^ new->flags) & SA_INTERRUPT)
-			return -EBUSY;
-
 		/* add new interrupt at end of irq queue */
 		do {
 			p = &old->next;
@@ -617,11 +594,9 @@
 	*p = new;
 
 	if (!shared) {
-		if (new->flags & SA_INTERRUPT)
-			set_intr_gate(0x20+irq,fast_interrupt[irq]);
-		else
-			set_intr_gate(0x20+irq,interrupt[irq]);
+		spin_lock(&irq_controller_lock);
 		unmask_irq(irq);
+		spin_unlock(&irq_controller_lock);
 	}
 	restore_flags(flags);
 	return 0;
@@ -676,10 +651,6 @@
 		save_flags(flags);
 		cli();
 		*p = action->next;
-		if (!irq[irq_action]) {
-			mask_irq(irq);
-			set_intr_gate(0x20+irq,bad_interrupt[irq]);
-		}
 		restore_flags(flags);
 		kfree(action);
 		return;
@@ -689,7 +660,7 @@
 
 unsigned long probe_irq_on (void)
 {
-	unsigned int i, irqs = 0, irqmask;
+	unsigned int i, irqs = 0;
 	unsigned long delay;
 
 	/* first, enable any unassigned irqs */
@@ -705,19 +676,17 @@
 		/* about 100ms delay */;
 
 	/* now filter out any obviously spurious interrupts */
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
-	return irqs & ~irqmask;
+	return irqs & ~cached_irq_mask;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-	unsigned int i, irqmask;
+	unsigned int i;
 
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 #ifdef DEBUG
-	printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask);
+	printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, cached_irq_mask);
 #endif
-	irqs &= irqmask;
+	irqs &= cached_irq_mask;
 	if (!irqs)
 		return 0;
 	i = ffz(~irqs);
@@ -729,10 +698,6 @@
 __initfunc(void init_IRQ(void))
 {
 	int i;
-	static unsigned char smptrap=0;
-	if(smptrap)
-		return;
-	smptrap=1;
 
 	/* set the clock to 100 Hz */
 	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
@@ -740,7 +705,7 @@
 	outb(LATCH >> 8 , 0x40);	/* MSB */
 
 	for (i = 0; i < NR_IRQS ; i++)
-		set_intr_gate(0x20+i,bad_interrupt[i]);
+		set_intr_gate(0x20+i,interrupt[i]);
 
 #ifdef __SMP__	
 	/*
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.1.36/linux/arch/i386/kernel/irq.h	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/irq.h	Mon May 12 10:35:37 1997
@@ -33,7 +33,6 @@
 
 static inline void irq_exit(int cpu, int irq)
 {
-	__cli();
 	hardirq_exit(cpu);
 	release_irqlock(cpu);
 }
@@ -64,18 +63,8 @@
 	"mov %dx,%es\n\t"
 
 /*
- * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
- * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
- * call the routines that do signal handling etc on return, and can have
- * more relaxed register-saving etc. They are also atomic, and are thus
- * suited for small, fast interrupts like the serial lines or the harddisk
- * drivers, which don't actually need signal handling etc.
- *
- * Also note that we actually save only those registers that are used in
- * C subroutines (%eax, %edx and %ecx), so if you do something weird,
- * you're on your own. The only segments that are saved (not counting the
- * automatic stack and code segment handling) are %ds and %es, and they
- * point to kernel space. No messing around with %fs here.
+ * These are used just for the "bad" interrupt handlers, 
+ * which just clear the mask and return..
  */
 #define SAVE_MOST \
 	"cld\n\t" \
@@ -96,92 +85,13 @@
 	"pop %es\n\t" \
 	"iret"
 
-/*
- * Some fast irq handlers might want to access saved registers (mostly
- * cs or flags)
- */
-
-struct fast_irq_regs {
-	long ecx;
-	long edx;
-	long eax;
-	int  xds;
-	int  xes;
-	long eip;
-	int  xcs;
-	long eflags;
-	long esp;
-	int  xss;
-};
-
-/*
- * The "inb" instructions are not needed, but seem to change the timings
- * a bit - without them it seems that the harddisk driver won't work on
- * all hardware. Arghh.
- */
-#define ACK_FIRST(mask,nr) \
-	"inb $0x21,%al\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
-	"movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
-	"outb %al,$0x21\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\tmovb $0x20,%al\n\t" \
-	"outb %al,$0x20\n\t"
-
-#define ACK_SECOND(mask,nr) \
-	"inb $0xA1,%al\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
-	"movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
-	"outb %al,$0xA1\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\tmovb $0x20,%al\n\t" \
-	"outb %al,$0xA0\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\toutb %al,$0x20\n\t"
-
-#define UNBLK_FIRST(mask) \
-	"inb $0x21,%al\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
-	"movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
-	"outb %al,$0x21\n\t"
-
-#define UNBLK_SECOND(mask) \
-	"inb $0xA1,%al\n\t" \
-	"jmp 1f\n" \
-	"1:\tjmp 1f\n" \
-	"1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
-	"movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
-	"outb %al,$0xA1\n\t"
-
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
 #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
 
-#ifdef	__SMP__
-
 #define GET_CURRENT \
-	"movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \
-	"movl 32(%ebx), %ebx\n\t" \
-	"shrl $22,%ebx\n\t" \
-	"andl $0x3C,%ebx\n\t" \
-	"movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t"
-	
-#else
-
-#define GET_CURRENT \
-	"movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
-	
-#endif
+	"movl %esp, %ebx\n\t" \
+	"andl $-8192, %ebx\n\t"
 
 #ifdef __SMP__
 
@@ -205,66 +115,30 @@
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(x) ":\n\t" \
 	"pushl $-1\n\t" \
-        SAVE_ALL \
-        "movl %esp,%eax\n\t" \
-        "pushl %eax\n\t" \
+	SAVE_ALL \
+	"movl %esp,%eax\n\t" \
+	"pushl %eax\n\t" \
 	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
-        "addl $4,%esp\n\t" \
+	"addl $4,%esp\n\t" \
 	"jmp ret_from_intr\n");
 
 #endif /* __SMP__ */
 
-#define BUILD_IRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
+#define BUILD_COMMON_IRQ() \
 __asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-	"pushl $-"#nr"-2\n\t" \
+	"\n" __ALIGN_STR"\n" \
+	"common_interrupt:\n\t" \
 	SAVE_ALL \
-	ACK_##chip(mask,(nr&7)) \
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
-	"addl $8,%esp\n\t" \
-	UNBLK_##chip(mask) \
-	"jmp ret_from_intr\n" \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-	SAVE_MOST \
-	ACK_##chip(mask,(nr&7)) \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
-	"addl $4,%esp\n\t" \
-	UNBLK_##chip(mask) \
-	RESTORE_MOST \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
-	SAVE_MOST \
-	ACK_##chip(mask,(nr&7)) \
-	RESTORE_MOST);
-	
-#define BUILD_TIMER_IRQ(chip,nr,mask) \
+	"pushl $ret_from_intr\n\t" \
+	"jmp "SYMBOL_NAME_STR(do_IRQ));
+
+#define BUILD_IRQ(chip,nr,mask) \
 asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
 __asm__( \
 "\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-	"pushl $-"#nr"-2\n\t" \
-	SAVE_ALL \
-	ACK_##chip(mask,(nr&7)) \
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
-	"pushl $" #nr "\n\t" \
-	"call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
-	"addl $8,%esp\n\t" \
-	UNBLK_##chip(mask) \
-	"jmp ret_from_intr\n");
+	"pushl $"#nr"-256\n\t" \
+	"jmp common_interrupt");
 
 /*
  * x86 profiling function, SMP safe. We might want to do this in
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.36/linux/arch/i386/kernel/process.c	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/kernel/process.c	Mon May 12 10:35:37 1997
@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/reboot.h>
+#include <linux/init.h>
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
 #include <linux/apm_bios.h>
 #endif
@@ -149,7 +150,8 @@
 	current->priority = -100;
 	while(1)
 	{
-		if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
+		if(cpu_data[smp_processor_id()].hlt_works_ok &&
+		 		!hlt_counter && !need_resched)
 			__asm("hlt");
 		/*
 		 * tq_scheduler currently assumes we're running in a process
@@ -183,7 +185,7 @@
 static int reboot_mode = 0;
 static int reboot_thru_bios = 0;
 
-void reboot_setup(char *str, int *ints)
+__initfunc(void reboot_setup(char *str, int *ints))
 {
 	while(1) {
 		switch (*str) {
@@ -324,11 +326,14 @@
 
 	pg0 [0] = 7;
 
-	/* Use `swapper_pg_dir' as our page directory.  Don't bother with
-	   `SET_PAGE_DIR' because interrupts are disabled and we're rebooting.
-	   This instruction flushes the TLB. */
+	/*
+	 * Use `swapper_pg_dir' as our page directory.  We bother with
+	 * `SET_PAGE_DIR' because although might be rebooting, but if we change
+	 * the way we set root page dir in the future, then we wont break a
+	 * seldom used feature ;)
+	 */
 
-	__asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory");
+	SET_PAGE_DIR(current,swapper_pg_dir);
 
 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
 	   this on booting to tell it to "Bypass memory test (also warm
@@ -473,6 +478,8 @@
 	int i;
 	struct pt_regs * childregs;
 
+	p->tss.tr = _TSS(nr);
+	p->tss.ldt = _LDT(nr);
 	p->tss.es = KERNEL_DS;
 	p->tss.cs = KERNEL_CS;
 	p->tss.ss = KERNEL_DS;
@@ -480,9 +487,8 @@
 	p->tss.fs = USER_DS;
 	p->tss.gs = USER_DS;
 	p->tss.ss0 = KERNEL_DS;
-	p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
-	p->tss.tr = _TSS(nr);
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+	p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p;
+	childregs = ((struct pt_regs *) (p->tss.esp0)) - 1;
 	p->tss.esp = (unsigned long) childregs;
 #ifdef __SMP__
 	p->tss.eip = (unsigned long) ret_from_smpfork;
@@ -496,7 +502,6 @@
 	childregs->eax = 0;
 	childregs->esp = esp;
 	p->tss.back_link = 0;
-	p->tss.ldt = _LDT(nr);
 	if (p->ldt) {
 		p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
 		if (p->ldt != NULL)
@@ -512,6 +517,7 @@
 		p->tss.io_bitmap[i] = ~0;
 	if (last_task_used_math == current)
 		__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.36/linux/arch/i386/kernel/ptrace.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/ptrace.c	Mon May 12 17:39:50 1997
@@ -34,18 +34,6 @@
  */
 #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * this routine will get a word off of the processes privileged stack. 
  * the offset is how far from the base addr as stored in the TSS.  
@@ -95,7 +83,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(vma, addr, 0);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -105,7 +93,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(vma, addr, 0);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -115,7 +103,7 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(vma, addr, 0);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
@@ -146,7 +134,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(vma, addr, 1);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -156,7 +144,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(vma, addr, 1);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -166,12 +154,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(vma, addr, 1);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		do_wp_page(tsk, vma, addr, 1);
+		handle_mm_fault(vma, addr, 1);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -381,7 +369,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		goto out;
 	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.36/linux/arch/i386/kernel/setup.c	Wed Apr 16 14:14:59 1997
+++ linux/arch/i386/kernel/setup.c	Tue May 13 17:48:58 1997
@@ -247,7 +247,7 @@
 static const char * i686model(unsigned int nr)
 {
 	static const char *model[] = {
-		"PPro A-step", "Pentium Pro"
+		"PPro A-step", "Pentium Pro", "2", "Pentium II"
 	};
 	if (nr < sizeof(model)/sizeof(char *))
 		return model[nr];
@@ -279,9 +279,10 @@
 int get_cpuinfo(char * buffer)
 {
         int i, len = 0;
+	int sep_bug;
         static const char *x86_cap_flags[] = {
                 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-                "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov",
+                "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
                 "16", "17", "18", "19", "20", "21", "22", "mmx",
                 "24", "25", "26", "27", "28", "29", "30", "31"
         };
@@ -321,10 +322,16 @@
                         else
                                 len += sprintf(buffer+len, 
                                                "stepping\t: unknown\n");
+
+			sep_bug = CD(have_cpuid) &&
+			          (CD(x86_capability) & 0x800) &&
+			          CD(x86_model) < 3 &&
+			          CD(x86_mask) < 3;
         
                         len += sprintf(buffer+len,
                                        "fdiv_bug\t: %s\n"
                                        "hlt_bug\t\t: %s\n"
+				       "sep_bug\t\t: %s\n"
                                        "fpu\t\t: %s\n"
                                        "fpu_exception\t: %s\n"
                                        "cpuid\t\t: %s\n"
@@ -332,6 +339,7 @@
                                        "flags\t\t:",
                                        CD(fdiv_bug) ? "yes" : "no",
                                        CD(hlt_works_ok) ? "no" : "yes",
+				       sep_bug ? "yes" : "no",
                                        CD(hard_math) ? "yes" : "no",
                                        (CD(hard_math) && ignore_irq13)
                                          ? "yes" : "no",
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.36/linux/arch/i386/kernel/signal.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/signal.c	Mon May 12 10:35:38 1997
@@ -318,6 +318,14 @@
 	unsigned long signr;
 	struct sigaction * sa;
 
+	/*
+	 *    We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if ((regs->xcs & 3) != 3)
+		return 1;
 	mask = ~current->blocked;
 	while ((signr = current->signal & mask)) {
 		/*
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.36/linux/arch/i386/kernel/smp.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/smp.c	Mon May 12 17:39:50 1997
@@ -1,5 +1,5 @@
 /*
- *	Intel MP v1.1/v1.4 specification support routines for multi-pentium 
+ *	Intel MP v1.1/v1.4 specification support routines for multi-pentium
  *	hosts.
  *
  *	(c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
@@ -46,14 +46,15 @@
 #include <asm/smp.h>
 #include <asm/io.h>
 
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
 #include "irq.h"
 
 extern unsigned long start_kernel, _etext;
 extern void update_one_process( struct task_struct *p,
-                                unsigned long ticks, unsigned long user,
-                                unsigned long system);
-void setup_APIC_clock (void);
-
+				unsigned long ticks, unsigned long user,
+				unsigned long system);
 /*
  *	Some notes on processor bugs:
  *
@@ -67,7 +68,7 @@
  *	Pentium
  *		There is a marginal case where REP MOVS on 100MHz SMP
  *	machines with B stepping processors can fail. XXX should provide
- *	an L1cache=Writethrough or L1cache=off option. 
+ *	an L1cache=Writethrough or L1cache=off option.
  *
  *		B stepping CPU's may hang. There are hardware work arounds
  *	for this. We warn about it in case your board doesnt have the work
@@ -91,12 +92,12 @@
  *	If this sounds worrying believe me these bugs are ___RARE___ and
  *	there's about nothing of note with C stepping upwards.
  */
- 
- 
+
+
 /*
  *	Why isn't this somewhere standard ??
  */
- 
+
 extern __inline int max(int a,int b)
 {
 	if(a>b)
@@ -121,7 +122,6 @@
 static unsigned int num_processors = 1;			/* Internal processor count				*/
 static unsigned long io_apic_addr = 0xFEC00000;		/* Address of the I/O apic (not yet used) 		*/
 unsigned char boot_cpu_id = 0;				/* Processor that is doing the boot up 			*/
-static unsigned char *kstack_base,*kstack_end;		/* Kernel stack list pointers 				*/
 static int smp_activated = 0;				/* Tripped once we need to start cross invalidating 	*/
 int apic_version[NR_CPUS];				/* APIC version number					*/
 static volatile int smp_commenced=0;			/* Tripped when we start scheduling 		    	*/
@@ -129,7 +129,6 @@
 unsigned long nlong = 0;				/* dummy used for apic_reg address + 0x20		*/
 unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC 		*/
 unsigned long apic_retval;				/* Just debugging the assembler.. 			*/
-unsigned char *kernel_stacks[NR_CPUS];			/* Kernel stack pointers for CPU's (debugging)		*/
 
 static volatile unsigned char smp_cpu_in_msg[NR_CPUS];	/* True if this processor is sending an IPI		*/
 
@@ -195,10 +194,10 @@
 	apic_write(APIC_EOI, 0);
 }
 
-/* 
+/*
  *	Checksum an MP configuration block.
  */
- 
+
 static int mpf_checksum(unsigned char *mp, int len)
 {
 	int sum=0;
@@ -210,7 +209,7 @@
 /*
  *	Processor encoding in an MP configuration block
  */
- 
+
 static char *mpc_family(int family,int model)
 {
 	static char n[32];
@@ -274,11 +273,11 @@
 
 	/* set the local APIC address */
 	apic_addr = (unsigned long)phys_to_virt((unsigned long)mpc->mpc_lapic);
-	
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
-	 
+	
 	while(count<mpc->mpc_length)
 	{
 		switch(*mpt)
@@ -290,13 +289,13 @@
 				if(m->mpc_cpuflag&CPU_ENABLED)
 				{
 					printk("Processor #%d %s APIC version %d\n",
-						m->mpc_apicid, 
+						m->mpc_apicid,
 						mpc_family((m->mpc_cpufeature&
 							CPU_FAMILY_MASK)>>8,
 							(m->mpc_cpufeature&
 								CPU_MODEL_MASK)>>4),
 						m->mpc_apicver);
-#ifdef SMP_DEBUG						
+#ifdef SMP_DEBUG
 					if(m->mpc_featureflag&(1<<0))
 						printk("    Floating point unit present.\n");
 					if(m->mpc_featureflag&(1<<7))
@@ -305,7 +304,7 @@
 						printk("    64 bit compare & exchange supported.\n");
 					if(m->mpc_featureflag&(1<<9))
 						printk("    Internal APIC present.\n");
-#endif						
+#endif
 					if(m->mpc_cpuflag&CPU_BOOTPROCESSOR)
 					{
 						SMP_PRINTK(("    Bootup CPU\n"));
@@ -313,10 +312,10 @@
 					}
 					else	/* Boot CPU already counted */
 						num_processors++;
-						
+
 					if(m->mpc_apicid>NR_CPUS)
 						printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
-					else						
+					else
 					{
 						cpu_present_map|=(1<<m->mpc_apicid);
 						apic_version[m->mpc_apicid]=m->mpc_apicver;
@@ -337,7 +336,7 @@
 					str));
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
-				break; 
+				break;
 			}
 			case MP_IOAPIC:
 			{
@@ -346,20 +345,20 @@
 				if(m->mpc_flags&MPC_APIC_USABLE)
 				{
 					apics++;
-	                                printk("I/O APIC #%d Version %d at 0x%lX.\n",
-	                                	m->mpc_apicid,m->mpc_apicver,
-	                                	m->mpc_apicaddr);
-	                                io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
-	                        }
-                                mpt+=sizeof(*m);
-                                count+=sizeof(*m); 
-                                break;
+					printk("I/O APIC #%d Version %d at 0x%lX.\n",
+						m->mpc_apicid,m->mpc_apicver,
+						m->mpc_apicaddr);
+					io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr);
+				}
+				mpt+=sizeof(*m);
+				count+=sizeof(*m);
+				break;
 			}
 			case MP_INTSRC:
 			{
 				struct mpc_config_intsrc *m=
 					(struct mpc_config_intsrc *)mpt;
-				
+
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
 				break;
@@ -376,29 +375,29 @@
 	}
 	if(apics>1)
 		printk("Warning: Multiple APIC's not supported.\n");
-	return num_processors;				
+	return num_processors;
 }
 
 /*
  *	Scan the memory blocks for an SMP configuration block.
  */
- 
+
 __initfunc(int smp_scan_config(unsigned long base, unsigned long length))
 {
 	unsigned long *bp=phys_to_virt(base);
 	struct intel_mp_floating *mpf;
-	
+
 	SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
 		bp,length));
 	if(sizeof(*mpf)!=16)
 		printk("Error: MPF size\n");
-	
+
 	while(length>0)
 	{
 		if(*bp==SMP_MAGIC_IDENT)
 		{
 			mpf=(struct intel_mp_floating *)bp;
-			if(mpf->mpf_length==1 && 
+			if(mpf->mpf_length==1 &&
 				!mpf_checksum((unsigned char *)bp,16) &&
 				(mpf->mpf_specification == 1
 				 || mpf->mpf_specification == 4) )
@@ -433,7 +432,7 @@
 					 *	We know that page 0 is not
 					 *	used.  Steal it for now!
 					 */
-			 
+			
 					cfg=pg0[0];
 					pg0[0] = (apic_addr | 7);
 					local_flush_tlb();
@@ -451,7 +450,7 @@
  *
  *	END OF HACK   END OF HACK   END OF HACK   END OF HACK   END OF HACK
  *
- */					
+ */
 					/*
 					 *	2 CPUs, numbered 0 & 1.
 					 */
@@ -513,6 +512,7 @@
 				nlong = boot_cpu_id<<24;	/* Dummy 'self' for bootup */
 				cpu_logical_map[0] = boot_cpu_id;
 				global_irq_holder = boot_cpu_id;
+				current->processor = boot_cpu_id;
 
 				printk("Processors: %d\n", num_processors);
 				/*
@@ -534,61 +534,37 @@
 
 extern unsigned char trampoline_data [];
 extern unsigned char trampoline_end  [];
+static unsigned char *trampoline_base;
 
 /*
  *	Currently trivial. Write the real->protected mode
  *	bootstrap into the page concerned. The caller
  *	has made sure it's suitably aligned.
  */
- 
-__initfunc(static void install_trampoline(unsigned char *mp))
+
+__initfunc(static unsigned long setup_trampoline(void))
 {
-	memcpy(mp, trampoline_data, trampoline_end - trampoline_data);
+	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+	return virt_to_phys(trampoline_base);
 }
 
 /*
- *	We are called very early to get the low memory for the trampoline/kernel stacks
- *	This has to be done by mm/init.c to parcel us out nice low memory. We allocate
- *	the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and
- *	other things).
+ *	We are called very early to get the low memory for the
+ *	SMP bootup trampoline page.
  */
- 
 __initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
 {
-	int size=(num_processors-1)*PAGE_SIZE;		/* Number of stacks needed */
-
-	/*
-	 *	Our stacks have to be below the 1Mb line, and mem_base on entry
-	 *	is 4K aligned.
-	 */
-	 
-	if(virt_to_phys((void *)(mem_base+size))>=0x9F000)
-		panic("smp_alloc_memory: Insufficient low memory for kernel stacks 0x%lx.\n", mem_base);
-	kstack_base=(void *)mem_base;
-	mem_base+=size;
-	kstack_end=(void *)mem_base;
-	return mem_base;
-}
-	
-/*
- *	Hand out stacks one at a time.
- */
- 
-__initfunc(static void *get_kernel_stack(void))
-{
-	void *stack=kstack_base;
-	if(kstack_base>=kstack_end)
-		return NULL;
-	kstack_base+=PAGE_SIZE;
-	return stack;
+	if (virt_to_phys((void *)mem_base) >= 0x9F000)
+		panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base);
+	trampoline_base = (void *)mem_base;
+	return mem_base + PAGE_SIZE;
 }
 
-
 /*
  *	The bootstrap kernel entry code has set these up. Save them for
  *	a given CPU
  */
- 
+
 __initfunc(void smp_store_cpu_info(int id))
 {
 	struct cpuinfo_x86 *c=&cpu_data[id];
@@ -615,7 +591,7 @@
  *	fired off. This allows the BP to have everything in order [we hope].
  *	At the end of this all the AP's will hit the system scheduling and off
  *	we go. Each AP will load the system gdt's and jump through the kernel
- *	init into idle(). At this point the scheduler will one day take over 
+ *	init into idle(). At this point the scheduler will one day take over
  * 	and give them jobs to do. smp_callin is a standard routine
  *	we use to track CPU's as they power up.
  */
@@ -634,74 +610,276 @@
 	extern void calibrate_delay(void);
 	int cpuid=GET_APIC_ID(apic_read(APIC_ID));
 	unsigned long l;
-	
+
 	/*
 	 *	Activate our APIC
 	 */
-	 
-	SMP_PRINTK(("CALLIN %d\n",smp_processor_id()));
+	
+	SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
  	l=apic_read(APIC_SPIV);
  	l|=(1<<8);		/* Enable */
  	apic_write(APIC_SPIV,l);
 
 	/*
-	 * Set up our APIC timer. 
+	 * Set up our APIC timer.
 	 */
 	setup_APIC_clock ();
 
  	sti();
 	/*
 	 *	Get our bogomips.
-	 */	
+	 */
 	calibrate_delay();
 	SMP_PRINTK(("Stack at about %p\n",&cpuid));
-	
+
 	/*
 	 *	Save our processor parameters
 	 */
  	smp_store_cpu_info(cpuid);
+
 	/*
 	 *	Allow the master to continue.
-	 */	
+	 */
 	set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+}
+
+static int cpucount = 0;
+
+extern int cpu_idle(void * unused);
+
+/*
+ *	Activate a secondary processor.
+ */
+__initfunc(int start_secondary(void *unused))
+{
+	smp_callin();
+	while (!smp_commenced)
+		barrier();
+	return cpu_idle(NULL);
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPU's - they just need to reload everything
+ * from the task structure
+ */
+__initfunc(void initialize_secondary(void))
+{
+	struct thread_struct * p = &current->tss;
+
 	/*
-	 *	Until we are ready for SMP scheduling
+	 * We don't actually need to load the full TSS,
+	 * basically just the stack pointer and the eip.
 	 */
-	load_ldt(0);
-	local_flush_tlb();
-	
-	while (cpu_number_map[cpuid] == -1)
-		barrier();
+	asm volatile("lldt %%ax": :"a" (p->ldt));
+	asm volatile("ltr %%ax": :"a" (p->tr));
+	asm volatile(
+		"movl %0,%%esp\n\t"
+		"jmp *%1"
+		:
+		:"r" (p->esp),"r" (p->eip));
+}
 
-	while(!task[cpuid] || current_set[cpuid] != task[cpu_number_map[cpuid]])
-		barrier();
+extern struct {
+	void * esp;
+	unsigned short ss;
+} stack_start;
 
-	local_flush_tlb();
-	load_TR(cpu_number_map[cpuid]);
+__initfunc(static void do_boot_cpu(int i))
+{
+	unsigned long cfg;
+	pgd_t maincfg;
+	struct task_struct *idle;
+	unsigned long send_status, accept_status;
+	int timeout, num_starts, j;
+	unsigned long start_eip;
 
-	while(!smp_commenced)
-		barrier();
-	
+	/*
+	 *	We need an idle process for each processor.
+	 */
+
+	kernel_thread(start_secondary, NULL, CLONE_PID);
+	cpucount++;
+
+	idle = task[cpucount];
+	if (!idle)
+		panic("No idle process for CPU %d\n", i);
+
+	idle->processor = i;
+	cpu_logical_map[cpucount] = i;
+	cpu_number_map[i] = cpucount;
+
+	/* start_eip had better be page-aligned! */
+	start_eip = setup_trampoline();
+
+	printk("Booting processor %d eip %lx: ", i, start_eip);	/* So we see what's up   */
+	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
+
+	/*
+	 *	This grunge runs the startup process for
+	 *	the targeted processor.
+	 */
+
+	SMP_PRINTK(("Setting warm reset code and vector.\n"));
+
+	CMOS_WRITE(0xa, 0xf);
 	local_flush_tlb();
+	SMP_PRINTK(("1.\n"));
+	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
+	SMP_PRINTK(("2.\n"));
+	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
+	SMP_PRINTK(("3.\n"));
+
+	maincfg=swapper_pg_dir[0];
+	((unsigned long *)swapper_pg_dir)[0]=0x102007;
+
+	/*
+	 *	Be paranoid about clearing APIC errors.
+	 */
+
+	if ( apic_version[i] & 0xF0 )
+	{
+		apic_write(APIC_ESR, 0);
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+	}
+
+	/*
+	 *	Status is now clean
+	 */
 	
-	SMP_PRINTK(("Commenced..\n"));
+	send_status = 	0;
+	accept_status = 0;
+
+	/*
+	 *	Starting actual IPI sequence...
+	 */
+
+	SMP_PRINTK(("Asserting INIT.\n"));
+
+	/*
+	 *	Turn INIT on
+	 */
+			
+	cfg=apic_read(APIC_ICR2);
+	cfg&=0x00FFFFFF;
+	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); 			/* Target chip     	*/
+	cfg=apic_read(APIC_ICR);
+	cfg&=~0xCDFFF;								/* Clear bits 		*/
+	cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+		| APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+	apic_write(APIC_ICR, cfg);						/* Send IPI */
+
+	udelay(200);
+	SMP_PRINTK(("Deasserting INIT.\n"));
+
+	cfg=apic_read(APIC_ICR2);
+	cfg&=0x00FFFFFF;
+	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
+	cfg=apic_read(APIC_ICR);
+	cfg&=~0xCDFFF;								/* Clear bits 		*/
+	cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+				| APIC_DEST_DM_INIT);
+	apic_write(APIC_ICR, cfg);						/* Send IPI */
+
+	/*
+	 *	Should we send STARTUP IPIs ?
+	 *
+	 *	Determine this based on the APIC version.
+	 *	If we don't have an integrated APIC, don't
+	 *	send the STARTUP IPIs.
+	 */
+
+	if ( apic_version[i] & 0xF0 )
+		num_starts = 2;
+	else
+		num_starts = 0;
+
+	/*
+	 *	Run STARTUP IPI loop.
+	 */
+
+	for (j = 1; !(send_status || accept_status)
+		    && (j <= num_starts) ; j++)
+	{
+		SMP_PRINTK(("Sending STARTUP #%d.\n",j));
+		apic_write(APIC_ESR, 0);
+		SMP_PRINTK(("After apic_write.\n"));
+
+		/*
+		 *	STARTUP IPI
+		 */
+
+		cfg=apic_read(APIC_ICR2);
+		cfg&=0x00FFFFFF;
+		apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
+		cfg=apic_read(APIC_ICR);
+		cfg&=~0xCDFFF;								/* Clear bits 		*/
+		cfg |= (APIC_DEST_FIELD
+			| APIC_DEST_DM_STARTUP
+			| (start_eip >> 12));						/* Boot on the stack 	*/
+		SMP_PRINTK(("Before start apic_write.\n"));
+		apic_write(APIC_ICR, cfg);						/* Kick the second 	*/
+
+		SMP_PRINTK(("Startup point 1.\n"));
+		timeout = 0;
+		do {
+			SMP_PRINTK(("Sleeping.\n")); udelay(1000000);
+			udelay(10);
+		} while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
+			  && (timeout++ < 1000));
+		udelay(200);
+		accept_status = (apic_read(APIC_ESR) & 0xEF);
+	}
+	SMP_PRINTK(("After Startup.\n"));
+
+	if (send_status)		/* APIC never delivered?? */
+		printk("APIC never delivered???\n");
+	if (accept_status)		/* Send accept error */
+		printk("APIC delivery error (%lx).\n", accept_status);
+
+	if( !(send_status || accept_status) )
+	{
+		for(timeout=0;timeout<50000;timeout++)
+		{
+			if(cpu_callin_map[0]&(1<<i))
+				break;				/* It has booted */
+			udelay(100);				/* Wait 5s total for a response */
+		}
+		if(cpu_callin_map[0]&(1<<i))
+		{
+			/* number CPUs logically, starting from 1 (BSP is 0) */
+#if 0
+			cpu_number_map[i] = cpucount;
+			cpu_logical_map[cpucount] = i;
+#endif
+		}
+		else
+		{
+			if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
+				printk("Stuck ??\n");
+			else
+				printk("Not responding.\n");
+		}
+	}
+	SMP_PRINTK(("CPU has booted.\n"));
+
+	swapper_pg_dir[0]=maincfg;
 	local_flush_tlb();
-	sti();
+
+	/* mark "stuck" area as not stuck */
+	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 }
 
+
 /*
  *	Cycle through the processors sending APIC IPI's to boot each.
  */
- 
+
 __initfunc(void smp_boot_cpus(void))
 {
 	int i;
-	int cpucount=0;
 	unsigned long cfg;
-	pgd_t maincfg;
-	void *stack;
-	extern unsigned long init_user_stack[];
-	
+
 	/*
 	 *	Initialize the logical to physical cpu number mapping
 	 */
@@ -712,12 +890,10 @@
 	/*
 	 *	Setup boot CPU information
 	 */
- 
-	kernel_stacks[boot_cpu_id]=(void *)init_user_stack;	/* Set up for boot processor first */
 
 	smp_store_cpu_info(boot_cpu_id);			/* Final full version of the data */
 
-	cpu_present_map |= (1 << smp_processor_id());
+	cpu_present_map |= (1 << hard_smp_processor_id());
 	cpu_number_map[boot_cpu_id] = 0;
 	active_kernel_processor=boot_cpu_id;
 
@@ -744,11 +920,11 @@
 	 */
 
 	apic_reg = ioremap(apic_addr,4096);
-	
+
 	if(apic_reg == NULL)
 		panic("Unable to map local apic.\n");
-		
-#ifdef SMP_DEBUG		
+
+#ifdef SMP_DEBUG
 	{
 		int reg;
 
@@ -785,11 +961,11 @@
 		SMP_PRINTK(("Getting LVT1: %x\n", reg));
 	}
 #endif
-	
+
 	/*
 	 *	Enable the local APIC
 	 */
- 
+
 	cfg=apic_read(APIC_SPIV);
 	cfg|=(1<<8);		/* Enable APIC */
 	apic_write(APIC_SPIV,cfg);
@@ -798,15 +974,15 @@
 
 	/*
 	 * Set up our local APIC timer:
-	 */			
+	 */
 	setup_APIC_clock ();
 
 	/*
 	 *	Now scan the cpu present map and fire up the other CPUs.
 	 */
- 
+
 	SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
-		
+
 	for(i=0;i<NR_CPUS;i++)
 	{
 		/*
@@ -814,213 +990,17 @@
 		 */
 		if (i == boot_cpu_id)
 			continue;
-		
+
 		if ((cpu_present_map & (1 << i))
 		    && (max_cpus < 0 || max_cpus > cpucount+1))
 		{
-			unsigned long send_status, accept_status;
-			int timeout, num_starts, j;
-			
-			/*
-			 *	We need a kernel stack for each processor.
-			 */
-			
-			stack=get_kernel_stack();	/* We allocated these earlier */
-			if(stack==NULL)
-				panic("No memory for processor stacks.\n");
-				
-			kernel_stacks[i]=(void *)phys_to_virt((unsigned long)stack);
-			install_trampoline(stack);
-
-			printk("Booting processor %d stack %p: ",i,stack);			/* So we set what's up   */
-
-			/*				
-			 *	This grunge runs the startup process for
-			 *	the targeted processor.
-			 */
-
-			SMP_PRINTK(("Setting warm reset code and vector.\n"));
-
-			/*
-			 *	Install a writable page 0 entry.
-			 */
-			 
-			cfg=pg0[0];
-			
-			CMOS_WRITE(0xa, 0xf);
-			pg0[0]=7;
-			local_flush_tlb();
-			SMP_PRINTK(("1.\n"));
-			*((volatile unsigned short *) phys_to_virt(0x469)) = ((unsigned long)stack)>>4;
-			SMP_PRINTK(("2.\n"));
-			*((volatile unsigned short *) phys_to_virt(0x467)) = 0;
-			SMP_PRINTK(("3.\n"));
-			
-			/*
-			 *	Protect it again
-			 */
-			 
-			pg0[0]= cfg;
-			local_flush_tlb();
-
-			/*	walken modif
-			 *	enable mapping of the first 4M at virtual
-			 *	address zero
-			 */
-
-			maincfg=swapper_pg_dir[0];
-			((unsigned long *)swapper_pg_dir)[0]=0x102007;
-
-			/* no need to local_flush_tlb :
-			   we are setting this up for the slave processor ! */
-
-			/*
-			 *	Be paranoid about clearing APIC errors.
-			 */
-
-			if ( apic_version[i] & 0xF0 )
-			{
-				apic_write(APIC_ESR, 0);
-				accept_status = (apic_read(APIC_ESR) & 0xEF);
-			}
-			
-			/*
-			 *	Status is now clean
-			 */
-			 
-			send_status = 	0;
-			accept_status = 0;
-
-			/*
-			 *	Starting actual IPI sequence...
-			 */
-
-			SMP_PRINTK(("Asserting INIT.\n"));
-
-			/*
-			 *	Turn INIT on
-			 */
-			 
-			cfg=apic_read(APIC_ICR2);
-			cfg&=0x00FFFFFF;
-			apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); 			/* Target chip     	*/
-			cfg=apic_read(APIC_ICR);
-			cfg&=~0xCDFFF;								/* Clear bits 		*/
-			cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
-				| APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
-			apic_write(APIC_ICR, cfg);						/* Send IPI */
-
-			udelay(200);
-			SMP_PRINTK(("Deasserting INIT.\n"));
-
-			cfg=apic_read(APIC_ICR2);
-			cfg&=0x00FFFFFF;
-			apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
-			cfg=apic_read(APIC_ICR);
-			cfg&=~0xCDFFF;								/* Clear bits 		*/
-			cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
-				| APIC_DEST_DM_INIT);
-			apic_write(APIC_ICR, cfg);						/* Send IPI */
-			
-			/*
-			 *	Should we send STARTUP IPIs ?
-			 *
-			 *	Determine this based on the APIC version.
-			 *	If we don't have an integrated APIC, don't
-			 *	send the STARTUP IPIs.
-			 */
-
-			if ( apic_version[i] & 0xF0 )
-				num_starts = 2;
-			else
-				num_starts = 0;
-
-			/*
-			 *	Run STARTUP IPI loop.
-			 */
-
-			for (j = 1; !(send_status || accept_status)
-				    && (j <= num_starts) ; j++)
-			{
-				SMP_PRINTK(("Sending STARTUP #%d.\n",j));
-
-				apic_write(APIC_ESR, 0);
-				SMP_PRINTK(("After apic_write.\n"));
-
-				/*
-				 *	STARTUP IPI
-				 */
-
-				cfg=apic_read(APIC_ICR2);
-				cfg&=0x00FFFFFF;
-				apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));			/* Target chip     	*/
-				cfg=apic_read(APIC_ICR);
-				cfg&=~0xCDFFF;								/* Clear bits 		*/
-				cfg |= (APIC_DEST_FIELD
-					| APIC_DEST_DM_STARTUP
-					| (((int)virt_to_phys(stack)) >> 12));					/* Boot on the stack 	*/		
-				SMP_PRINTK(("Before start apic_write.\n"));
-				apic_write(APIC_ICR, cfg);						/* Kick the second 	*/
-
-				SMP_PRINTK(("Startup point 1.\n"));
-				timeout = 0;
-				do {
-				        SMP_PRINTK(("Sleeping.\n")); udelay(1000000);	
-					udelay(10);
-				} while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
-					  && (timeout++ < 1000));
-				udelay(200);
-
-				accept_status = (apic_read(APIC_ESR) & 0xEF);
-			}
-			SMP_PRINTK(("After Startup.\n"));
-
-			if (send_status)		/* APIC never delivered?? */
-				printk("APIC never delivered???\n");
-			if (accept_status)		/* Send accept error */
-				printk("APIC delivery error (%lx).\n", accept_status);
-			
-			if( !(send_status || accept_status) )
-			{
-				for(timeout=0;timeout<50000;timeout++)
-				{
-					if(cpu_callin_map[0]&(1<<i))
-						break;				/* It has booted */
-					udelay(100);				/* Wait 5s total for a response */
-				}
-				if(cpu_callin_map[0]&(1<<i))
-				{
-					cpucount++;
-					/* number CPUs logically, starting from 1 (BSP is 0) */
-					cpu_number_map[i] = cpucount;
-					cpu_logical_map[cpucount] = i;
-				}
-				else
-				{
-					if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
-						printk("Stuck ??\n");
-					else
-						printk("Not responding.\n");
-				}
-			}
-			SMP_PRINTK(("CPU has booted.\n"));
-
-                        /*      walken modif
-                         *      restore mapping of the first 4M
-                         */
-
-                        swapper_pg_dir[0]=maincfg;
-                        
-                        local_flush_tlb();
-
-			/* mark "stuck" area as not stuck */
-			*((volatile unsigned long *)phys_to_virt(8192)) = 0;
+			do_boot_cpu(i);
 		}
-		
-		/* 
+
+		/*
 		 *	Make sure we unmap all failed CPUs
 		 */
-		 
+		
 		if (cpu_number_map[i] == -1)
 			cpu_present_map &= ~(1 << i);
 	}
@@ -1056,12 +1036,12 @@
 	/*
 	 *	Allow the user to impress friends.
 	 */
-	
+
 	SMP_PRINTK(("Before bogomips.\n"));
 	if(cpucount==0)
 	{
 		printk("Error: only one processor found.\n");
-		cpu_present_map=(1<<smp_processor_id());
+		cpu_present_map=(1<<hard_smp_processor_id());
 	}
 	else
 	{
@@ -1071,8 +1051,8 @@
 			if(cpu_present_map&(1<<i))
 				bogosum+=cpu_data[i].udelay_val;
 		}
-		printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", 
-			cpucount+1, 
+		printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+			cpucount+1,
 			(bogosum+2500)/500000,
 			((bogosum+2500)/5000)%100);
 		SMP_PRINTK(("Before bogocount - setting activated=1.\n"));
@@ -1096,7 +1076,7 @@
  *	IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That
  *	will also boost performance.
  */
- 
+
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	unsigned long flags;
@@ -1109,11 +1089,11 @@
 	/*
 	 *	During boot up send no messages
 	 */
-	 
+	
 	if(!smp_activated || !smp_commenced)
 		return;
-		
-	
+
+
 	/*
 	 *	Skip the reschedule if we are waiting to clear a
 	 *	message at this time. The reschedule cannot wait
@@ -1121,7 +1101,7 @@
 	 */
 
 	switch (msg) {
-		case MSG_RESCHEDULE:	
+		case MSG_RESCHEDULE:
 			irq = 0x30;
 			if (smp_cpu_in_msg[p])
 				return;
@@ -1148,21 +1128,21 @@
 	 *	no data and can occur during a flush.. guess what panic
 	 *	I got to notice this bug...
 	 */
-	 
+	
 	/*
 	 *	We are busy
 	 */
-	 	
-	smp_cpu_in_msg[p]++;
 	
+	smp_cpu_in_msg[p]++;
+
 /*	printk("SMP message pass #%d to %d of %d\n",
 		p, msg, target);*/
-	
+
 	/*
 	 *	Wait for the APIC to become ready - this should never occur. Its
 	 *	a debugging check really.
 	 */
-	 
+	
 	while(ct<1000)
 	{
 		cfg=apic_read(APIC_ICR);
@@ -1171,14 +1151,14 @@
 		ct++;
 		udelay(10);
 	}
-	
+
 	/*
 	 *	Just pray... there is nothing more we can do
 	 */
-	 
+	
 	if(ct==1000)
 		printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
-		
+
 	/*
 	 *	Program the APIC to deliver the IPI
 	 */
@@ -1190,12 +1170,12 @@
 	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target));			/* Target chip     		*/
 	cfg=apic_read(APIC_ICR);
 	cfg&=~0xFDFFF;								/* Clear bits 			*/
-	cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq;				/* Send an IRQ 13		*/		
+	cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq;				/* Send an IRQ 13		*/
 
 	/*
 	 *	Set the target requirement
 	 */
-	 
+	
 	if(target==MSG_ALL_BUT_SELF)
 	{
 		cfg|=APIC_DEST_ALLBUT;
@@ -1213,18 +1193,18 @@
 		target_map=(1<<target);
 		cpu_callin_map[0]=0;
 	}
-		
+
 	/*
 	 *	Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	 
+	
 	apic_write(APIC_ICR, cfg);
 	__restore_flags(flags);
-	
+
 	/*
 	 *	Spin waiting for completion
 	 */
-	 
+	
 	switch(wait)
 	{
 		int stuck;
@@ -1247,17 +1227,17 @@
 					clear_bit(p, &smp_invalidate_needed);
 				--stuck;
 				if (!stuck) {
-					printk("stuck on smp_invalidate_needed IPI wait\n");
+					printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p);
 					break;
 				}
 			}
 			break;
 	}
-	
+
 	/*
 	 *	Record our completion
 	 */
-	 
+	
 	smp_cpu_in_msg[p]--;
 }
 
@@ -1266,14 +1246,17 @@
  *	even with IRQ's off. We have to avoid a pair of crossing flushes
  *	or we are doomed.  See the notes about smp_message_pass.
  */
- 
+
 void smp_flush_tlb(void)
 {
 	unsigned long flags;
+
+#if 0
 	if(smp_activated && smp_processor_id()!=active_kernel_processor) {
 		printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
 		*(char *)0=0;
 	}
+#endif
 /*	printk("SMI-");*/
 
 	/*
@@ -1282,30 +1265,30 @@
 	 *	may issue a tlb flush. If you break any one of those three change this to an atomic
 	 *	bus locked or.
 	 */
-	
+
 	smp_invalidate_needed=cpu_present_map;
-	
+
 	/*
 	 *	Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
 	 *	ensure they don't do a spurious flush tlb or miss one.
 	 */
-	 
+	
 	__save_flags(flags);
 	__cli();
 	smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
-	
+
 	/*
 	 *	Flush the local TLB
 	 */
-	 
-	local_flush_tlb();
 	
+	local_flush_tlb();
+
 	__restore_flags(flags);
-	
+
 	/*
 	 *	Completed.
 	 */
-	 
+	
 /*	printk("SMID\n");*/
 }
 
@@ -1315,14 +1298,14 @@
  *
  * We do profiling in every local tick, statistics/rescheduling
  * happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing a 4 bytes multiplier
+ * multiplier is 1 and it can be changed by writing the new multiplier
  * value into /proc/profile.
  */
 
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 
-static inline void smp_local_timer_interrupt(struct pt_regs * regs)
+void smp_local_timer_interrupt(struct pt_regs * regs)
 {
 	int cpu = smp_processor_id();
 
@@ -1367,7 +1350,7 @@
 				kstat.cpu_user += user;
 
 			kstat.cpu_system += system;
-		
+
 		} else {
 #ifdef __SMP_PROF__
 			if (test_bit(cpu,&smp_idle_map))
@@ -1386,14 +1369,11 @@
 	 * We take the 'long' return path, and there every subsystem
 	 * grabs the apropriate locks (kernel lock/ irq lock).
 	 *
-	 * FIXME: we want to decouple profiling from the 'long path'.
+	 * we might want to decouple profiling from the 'long path',
+	 * and do the profiling totally in assembly.
 	 *
 	 * Currently this isnt too much of an issue (performancewise),
 	 * we can take more than 100K local irqs per second on a 100 MHz P5.
-	 * [ although we notice need_resched too early, thus the way we
-	 *   schedule (deliver signals and handle bhs) changes. ]
-	 *
-	 * Possibly we could solve these problems with 'smart irqs'.
 	 */
 }
 
@@ -1401,6 +1381,9 @@
  * Local APIC timer interrupt. This is the most natural way for doing
  * local interrupts, but local timer interrupts can be emulated by
  * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ *
+ * [ if a single-CPU system runs an SMP kernel then we call the local
+ *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
 void smp_apic_timer_interrupt(struct pt_regs * regs)
 {
@@ -1415,7 +1398,7 @@
 	smp_local_timer_interrupt(regs);
 }
 
-/*	
+/*
  *	Reschedule call back
  */
 asmlinkage void smp_reschedule_interrupt(void)
@@ -1437,11 +1420,11 @@
  */
 asmlinkage void smp_invalidate_interrupt(void)
 {
-	if (clear_bit(smp_processor_id(), &smp_invalidate_needed))
+	if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
 		local_flush_tlb();
 
 	ack_APIC_irq ();
-}	
+}
 
 /*
  *	CPU halt call-back
@@ -1471,11 +1454,11 @@
  * but we do not accept timer interrupts yet. We only allow the BP
  * to calibrate.
  */
-static unsigned int get_8254_timer_count (void)
+__initfunc(static unsigned int get_8254_timer_count (void))
 {
 	unsigned int count;
 
-        outb_p(0x00, 0x43);
+	outb_p(0x00, 0x43);
 	count = inb_p(0x40);
 	count |= inb_p(0x40) << 8;
 
@@ -1500,7 +1483,7 @@
 
 void setup_APIC_timer (unsigned int clocks)
 {
-	unsigned long lvtt1_value; 
+	unsigned long lvtt1_value;
 	unsigned int tmp_value;
 
 	/*
@@ -1508,8 +1491,8 @@
 	 * mode. With the IO APIC we can re-route the external timer
 	 * interrupt and broadcast it as an NMI to all CPUs, so no pain.
 	 *
-	 * NOTE: this trap vector (0x41) and the gate in BUILD_SMP_TIMER_INTERRUPT
-	 * should be the same ;)
+	 * NOTE: this trap vector (0x41) and the gate in
+	 * BUILD_SMP_TIMER_INTERRUPT should be the same ;)
 	 */
 	tmp_value = apic_read(APIC_LVTT);
 	lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41;
@@ -1526,7 +1509,7 @@
 	apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-void wait_8254_wraparound (void)
+__initfunc(void wait_8254_wraparound (void))
 {
 	unsigned int curr_count, prev_count=~0;
 	int delta;
@@ -1560,11 +1543,12 @@
  * APIC irq that way.
  */
 
-int calibrate_APIC_clock (void)
+__initfunc(int calibrate_APIC_clock (void))
 {
 	unsigned long long t1,t2;
 	long tt1,tt2;
 	long calibration_result;
+	int i;
 
 	printk("calibrating APIC timer ... ");
 
@@ -1589,10 +1573,12 @@
 	RTDSC(t1);
 	tt1=apic_read(APIC_TMCCT);
 
+#define LOOPS (HZ/10)
 	/*
-	 * lets wait until we get to the next wrapround:
+	 * lets wait LOOPS wraprounds:
 	 */
-	wait_8254_wraparound ();
+	for (i=0; i<LOOPS; i++)
+		wait_8254_wraparound ();
 
 	tt2=apic_read(APIC_TMCCT);
 	RTDSC(t2);
@@ -1605,46 +1591,47 @@
 	 * underflown to be exact, as the timer counts down ;)
 	 */
 
-	calibration_result = (tt1-tt2)*APIC_DIVISOR;
+	calibration_result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
 
-	printk("\n..... %ld CPU clocks in 1 timer chip tick.\n",
-			 (unsigned long)(t2-t1));
+	SMP_PRINTK(("\n..... %ld CPU clocks in 1 timer chip tick.",
+			 (unsigned long)(t2-t1)/LOOPS));
 
-	printk("..... %ld APIC bus clocks in 1 timer chip tick.\n",
-			 calibration_result);
+	SMP_PRINTK(("\n..... %ld APIC bus clocks in 1 timer chip tick.",
+			 calibration_result));
 
 
-	printk("..... CPU clock speed is %ld.%ld MHz.\n", 
-		((long)(t2-t1))/(1000000/HZ),
-		((long)(t2-t1))%(1000000/HZ)  );
+	printk("\n..... CPU clock speed is %ld.%04ld MHz.\n",
+		((long)(t2-t1)/LOOPS)/(1000000/HZ),
+		((long)(t2-t1)/LOOPS)%(1000000/HZ)  );
 
-	printk("..... APIC bus clock speed is %ld.%ld MHz.\n", 
+	printk("..... APIC bus clock speed is %ld.%04ld MHz.\n",
 		calibration_result/(1000000/HZ),
 		calibration_result%(1000000/HZ)  );
+#undef LOOPS
 
 	return calibration_result;
 }
 
 static unsigned int calibration_result;
 
-void setup_APIC_clock (void)
+__initfunc(void setup_APIC_clock (void))
 {
 	int cpu = smp_processor_id();
-	unsigned long flags; 
+	unsigned long flags;
 
 	static volatile int calibration_lock;
 
 	save_flags(flags);
 	cli();
 
-	printk("setup_APIC_clock() called.\n");
+	SMP_PRINTK(("setup_APIC_clock() called.\n"));
 
 	/*
 	 * [ setup_APIC_clock() is called from all CPUs, but we want
 	 *   to do this part of the setup only once ... and it fits
 	 *   here best ]
 	 */
-	if (!set_bit(0,&calibration_lock)) {
+	if (!test_and_set_bit(0,&calibration_lock)) {
 
 		calibration_result=calibrate_APIC_clock();
 		/*
@@ -1656,9 +1643,9 @@
 		/*
 		 * Other CPU is calibrating, wait for finish:
 		 */
-		printk("waiting for other CPU calibrating APIC timer ... ");
+		SMP_PRINTK(("waiting for other CPU calibrating APIC ... "));
 		while (calibration_lock == 1);
-		printk("done, continuing.\n");
+		SMP_PRINTK(("done, continuing.\n"));
 	}
 
 /*
@@ -1669,16 +1656,8 @@
 	prof_counter[cpu] = prof_multiplier[cpu] = 1;
 
 	/*
-	 * FIXME: i sporadically see booting problems (keyboard irq is
-	 * lost, looks like the  timer irq isnt working or some irq
-	 * lock is messed up). Once we reboot the bug doesnt showu
-	 * up anymore.
-	 *
-	 * i'm quite certain it's a timing problem/race condition in
-	 * the bootup logic, not a hw bug. It might have been gone
-	 * meanwhile, tell me if you see it.
+	 * We ACK the APIC, just in case there is something pending.
 	 */
-
 	ack_APIC_irq ();
 
 	restore_flags(flags);
@@ -1686,7 +1665,7 @@
 
 /*
  * the frequency of the profiling timer can be changed
- * by writing 4 bytes into /proc/profile.
+ * by writing a multiplier value into /proc/profile.
  *
  * usually you want to run this on all CPUs ;)
  */
@@ -1697,8 +1676,8 @@
 
 	/*
 	 * Sanity check. [at least 500 APIC cycles should be
-	 * between APIC interrupts as a rule of thumb, rather be
-	 * careful as irq flooding renders the system unusable]
+	 * between APIC interrupts as a rule of thumb, to avoid
+	 * irqs flooding us]
 	 */
 	if ( (!multiplier) || (calibration_result/multiplier < 500))
 		return -EINVAL;
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.36/linux/arch/i386/kernel/time.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/kernel/time.c	Mon May 12 10:35:38 1997
@@ -23,6 +23,7 @@
 #include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -379,11 +380,15 @@
 	do_timer(regs);
 /*
  * In the SMP case we use the local APIC timer interrupt to do the
- * profiling.
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
  */
 #ifndef __SMP__
 	if (!user_mode(regs))
 		x86_do_profile(regs->eip);
+#else
+	if (!smp_found_config)
+		smp_local_timer_interrupt(regs);
 #endif
 
 	/*
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/trampoline.S linux/arch/i386/kernel/trampoline.S
--- v2.1.36/linux/arch/i386/kernel/trampoline.S	Sun Jan 26 02:07:04 1997
+++ linux/arch/i386/kernel/trampoline.S	Mon May 12 10:35:38 1997
@@ -21,13 +21,9 @@
  *	and IP is zero.  Thus, data addresses need to be absolute
  *	(no relocation) and are taken with regard to r_base.
  *
- *	On the transition to protected mode, this page appears at
- *	address 8192, so protected mode addresses are with regard
- *	to p_base.
- *
  *	If you work on this file, check the object module with objdump
  *	--full-contents --reloc to make sure there are no relocation
- *	entries.
+ *	entries except for the gdt one..
  */
 
 #include <linux/linkage.h>
@@ -39,15 +35,10 @@
 
 ENTRY(trampoline_data)
 r_base = .
-p_base = . - 8192
 
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
-	mov	%ax, %cx	# Pass stack info to the 32bit boot
-	shl	$4, %cx		# Segment -> Offset
-	add	$4096, %cx	# End of page is wanted
-
 	mov	$1, %bx		# Flag an SMP trampoline
 	cli			# We should be safe anyway
 
@@ -71,37 +62,7 @@
 
 gdt_48:
 	.word	0x0800			# gdt limit = 2048, 256 GDT entries
-	.word	gdt - p_base, 0x0	# gdt base = gdt (first SMP CPU)
-					# we load the others with first table
-					# saves rewriting gdt_48 for each
-gdt:
-	.word	0, 0, 0, 0	# dummy
-
-	.word	0, 0, 0, 0	# unused
-
-# walken modif
-
-	.word	0xFFFF		# 4 Gb - (0x100000*0x1000 = 4Gb)
-	.word	0x0000		# base address = 0
-	.word	0x9A00		# code read / exec
-	.word	0x00CF		# granularity = 4096, 386 (+5th nibble of limit)
-
-	.word	0xFFFF		# 4 Gb - (0x100000*0x1000 = 4Gb)
-	.word	0x0000		# base address = 0
-	.word	0x9200		# data read / write
-	.word	0x00CF		# granularity = 4096, 386 (+5th nibble of limit)
-
-# walken modif
-
-#	.word	0x07FF		# 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-#	.word	0x0000		# base address = 0
-#	.word	0x9A00		# code read / exec
-#	.word	0x00C0		# granularity = 4096, 386
-
-#	.word	0x07FF		# 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb)
-#	.word	0x0000		# base address = 0
-#	.word	0x9200		# data read / write
-#	.word	0x00C0		# granularity = 4096, 386
+	.long	gdt-0xc0000000		# gdt base = gdt (first SMP CPU)
 
 .globl SYMBOL_NAME(trampoline_end)
 SYMBOL_NAME_LABEL(trampoline_end)
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.36/linux/arch/i386/kernel/traps.c	Wed Apr 16 14:14:59 1997
+++ linux/arch/i386/kernel/traps.c	Mon May 12 10:35:38 1997
@@ -23,10 +23,12 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
@@ -121,7 +123,7 @@
 	unsigned long esp;
 	unsigned short ss;
 	unsigned long *stack, addr, module_start, module_end;
-	extern char start_kernel, _etext;
+	extern char _stext, _etext;
 
 	esp = (unsigned long) &regs->esp;
 	ss = KERNEL_DS;
@@ -129,8 +131,8 @@
 		esp = regs->esp;
 		ss = regs->xss & 0xffff;
 	}
-	printk("CPU:    %d\n", smp_processor_id());
-	printk("EIP:    %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags);
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]\nEFLAGS: %08lx\n",
+		smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
@@ -138,10 +140,8 @@
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
 	store_TR(i);
-	if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
-		printk("Corrupted stack page\n");
 	printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
-		current->comm, current->pid, 0xffff & i, current->kernel_stack_page);
+		current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current);
 	stack = (unsigned long *) esp;
 	for(i=0; i < kstack_depth_to_print; i++) {
 		if (((long) stack & 4095) == 0)
@@ -166,7 +166,7 @@
 		 * down the cause of the crash will be able to figure
 		 * out the call path that was taken.
 		 */
-		if (((addr >= (unsigned long) &start_kernel) &&
+		if (((addr >= (unsigned long) &_stext) &&
 		     (addr <= (unsigned long) &_etext)) ||
 		    ((addr >= module_start) && (addr <= module_end))) {
 			if (i && ((i % 8) == 0))
@@ -181,13 +181,19 @@
 	printk("\n");
 }	
 
+spinlock_t die_lock;
+
 /*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
 	if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3)
 		return;
 	console_verbose();
+	spin_lock_irq(&die_lock);
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
+do { int i=2000000000; while (i) i--; } while (0);
+do { int i=2000000000; while (i) i--; } while (0);
+	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
 
@@ -235,18 +241,45 @@
 	unlock_kernel();
 }
 
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
 {
-	printk("NMI\n"); show_registers(regs);
-#ifdef CONFIG_SMP_NMI_INVAL
-	smp_flush_tlb_rcv();
-#else
-#ifndef CONFIG_IGNORE_NMI
 	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
-	printk("You probably have a hardware problem with your RAM chips or a\n");
-	printk("power saving mode enabled.\n");
-#endif	
-#endif
+	printk("You probably have a hardware problem with your RAM chips\n");
+}	
+
+static void io_check_error(unsigned char reason, struct pt_regs * regs)
+{
+	unsigned long i;
+
+	printk("NMI: IOCK error (debug interrupt?)\n");
+	show_registers(regs);
+
+	/* Re-enable the IOCK line, wait for a few seconds */
+	reason |= 8;
+	outb(reason, 0x61);
+	i = 2000;
+	while (--i) udelay(1000);
+	reason &= ~8;
+	outb(reason, 0x61);
+}
+
+static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+	printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+	printk("Dazed and confused, but trying to continue\n");
+	printk("Do you have a strange power saving mode enabled?\n");
+}
+
+asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+{
+	unsigned char reason = inb(0x61);
+
+	if (reason & 0x80)
+		mem_parity_error(reason, regs);
+	if (reason & 0x40)
+		io_check_error(reason, regs);
+	if (!(reason & 0xc0))
+		unknown_nmi_error(reason, regs);
 }
 
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -380,15 +413,7 @@
 {
 	int i;
 	struct desc_struct * p;
-	static int smptrap=0;
-	
-	if(smptrap)
-	{
-		__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
-		load_ldt(0);
-		return;
-	}
-	smptrap++;
+
 	if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
 		EISA_bus = 1;
 	set_call_gate(&default_ldt,lcall7);
diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.1.36/linux/arch/i386/kernel/vm86.c	Thu Feb 27 10:57:29 1997
+++ linux/arch/i386/kernel/vm86.c	Mon May 12 10:35:38 1997
@@ -81,8 +81,8 @@
 		printk("vm86: could not access userspace vm86_info\n");
 		do_exit(SIGSEGV);
 	}
-	current->tss.esp0 = current->saved_kernel_stack;
-	current->saved_kernel_stack = 0;
+	current->tss.esp0 = current->tss.saved_esp0;
+	current->tss.saved_esp0 = 0;
 	ret = KVM86->regs32;
 	unlock_kernel();
 	return ret;
@@ -137,7 +137,7 @@
 
 	lock_kernel();
 	tsk = current;
-	if (tsk->saved_kernel_stack)
+	if (tsk->tss.saved_esp0)
 		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -187,7 +187,7 @@
 
 	/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
 	ret = -EPERM;
-	if (tsk->saved_kernel_stack)
+	if (tsk->tss.saved_esp0)
 		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -247,7 +247,7 @@
  * Save old state, set default return value (%eax) to 0
  */
 	info->regs32->eax = 0;
-	tsk->saved_kernel_stack = tsk->tss.esp0;
+	tsk->tss.saved_esp0 = tsk->tss.esp0;
 	tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
 
 	tsk->tss.screen_bitmap = info->screen_bitmap;
@@ -601,11 +601,17 @@
 static inline int task_valid(struct task_struct *tsk)
 {
 	struct task_struct *p;
+	int ret = 0;
 
+	read_lock(&tasklist_lock);
 	for_each_task(p) {
-		if ((p == tsk) && (p->sig)) return 1;
+		if ((p == tsk) && (p->sig)) {
+			ret = 1;
+			break;
+		}
 	}
-	return 0;
+	read_unlock(&tasklist_lock);
+	return ret;
 }
 
 static inline void handle_irq_zombies(void)
diff -u --recursive --new-file v2.1.36/linux/arch/i386/lib/locks.S linux/arch/i386/lib/locks.S
--- v2.1.36/linux/arch/i386/lib/locks.S	Sun Jan 26 02:07:05 1997
+++ linux/arch/i386/lib/locks.S	Mon May 12 10:35:38 1997
@@ -10,7 +10,6 @@
 	 * %eax contains callers PC and %edx holds this cpu ID.
 	 */
 ENTRY(__lock_kernel)
-	pushl	%eax		! return address
 1:
 	lock
 	btsl	$0, SYMBOL_NAME(kernel_flag)
@@ -21,8 +20,10 @@
 	lock
 	btrl	%dl, SYMBOL_NAME(smp_invalidate_needed)
 	jnc	0f
+	pushl	%eax
 	movl	%cr3, %eax
 	movl	%eax, %cr3
+	popl	%eax
 0:
 	btl	$0, SYMBOL_NAME(kernel_flag)
 	jc	2b
diff -u --recursive --new-file v2.1.36/linux/arch/i386/lib/semaphore.S linux/arch/i386/lib/semaphore.S
--- v2.1.36/linux/arch/i386/lib/semaphore.S	Wed Jan 15 09:32:17 1997
+++ linux/arch/i386/lib/semaphore.S	Mon May 12 17:39:50 1997
@@ -13,28 +13,31 @@
  * there is contention on the semaphore.
  */
 ENTRY(__down_failed)
-	pushl %eax	/* return address */
+	pushl %eax	/* save %eax */
 	pushl %edx	/* save %edx */
 	pushl %ecx	/* save %ecx (and argument) */
 	call SYMBOL_NAME(__down)
 	popl %ecx	/* restore %ecx (count on __down not changing it) */
 	popl %edx	/* restore %edx */
+	popl %eax	/* restore %eax */
 	ret
 
 ENTRY(__down_failed_interruptible)
-	pushl %eax	/* return address */
+	pushl %eax	/* save %eax */
 	pushl %edx	/* save %edx */
 	pushl %ecx	/* save %ecx (and argument) */
 	call SYMBOL_NAME(__down_interruptible)
 	popl %ecx	/* restore %ecx (count on __down_interruptible not changing it) */
 	popl %edx	/* restore %edx */
+	popl %eax	/* restore %eax */
 	ret
 
 ENTRY(__up_wakeup)
-	pushl %eax	/* return address */
+	pushl %eax	/* save %eax */
 	pushl %edx	/* save %edx */
 	pushl %ecx	/* save %ecx (and argument) */
 	call SYMBOL_NAME(__up)
 	popl %ecx	/* restore %ecx (count on __up not changing it) */
 	popl %edx	/* restore %edx */
+	popl %eax	/* restore %eax */
 	ret
diff -u --recursive --new-file v2.1.36/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.36/linux/arch/i386/mm/fault.c	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/mm/fault.c	Mon May 12 17:39:50 1997
@@ -49,7 +49,7 @@
 	start &= PAGE_MASK;
 
 	for (;;) {
-		do_wp_page(current, vma, start, 1);
+		handle_mm_fault(vma, start, 1);
 		if (!size)
 			break;
 		size--;
@@ -86,10 +86,6 @@
  */
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-	void (*handler)(struct task_struct *,
-			struct vm_area_struct *,
-			unsigned long,
-			int);
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
 	struct vm_area_struct * vma;
@@ -128,10 +124,8 @@
  */
 good_area:
 	write = 0;
-	handler = do_no_page;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
-			handler = do_wp_page;
 #ifdef TEST_VERIFY_AREA
 			if (regs->cs == KERNEL_CS)
 				printk("WP fault at %08lx\n", regs->eip);
@@ -148,7 +142,7 @@
 			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 				goto bad_area;
 	}
-	handler(tsk, vma, address, write);
+	handle_mm_fault(vma, address, write);
 	up(&mm->mmap_sem);
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
@@ -169,7 +163,10 @@
 
 	/* Are we prepared to handle this fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
-		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup);
+		printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+			current->comm,
+			regs->eip,
+			fixup);
 		regs->eip = fixup;
 		goto out;
 	}
diff -u --recursive --new-file v2.1.36/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.36/linux/arch/i386/mm/init.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/i386/mm/init.c	Mon May 12 10:35:38 1997
@@ -139,12 +139,23 @@
 #define write_cr4	".byte 0x0f,0x22,0xe0"
 #endif
 
-#define set_in_cr4(x) \
-__asm__(read_cr4 "\n\t" \
-	"orl %0,%%eax\n\t" \
-	write_cr4 \
-	: : "i" (x) \
-	:"ax");
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+unsigned long mmu_cr4_features __initdata = 0;
+
+static inline void set_in_cr4(unsigned long mask)
+{
+	mmu_cr4_features |= mask;
+	__asm__(read_cr4 "\n\t"
+		"orl %0,%%eax\n\t"
+		write_cr4
+		: : "irg" (mask)
+		:"ax");
+}
 
 /*
  * paging_init() sets up the page tables - note that the first 4MB are
diff -u --recursive --new-file v2.1.36/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.1.36/linux/arch/i386/vmlinux.lds	Wed Apr 16 14:15:00 1997
+++ linux/arch/i386/vmlinux.lds	Mon May 12 10:35:38 1997
@@ -13,6 +13,7 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x9090
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.1.36/linux/arch/m68k/Makefile	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/Makefile	Mon May 12 10:35:38 1997
@@ -24,17 +24,7 @@
 	CROSS_COMPILE = m68k-linux-
 endif
 
-#
-# Set these to indicate how to link it..
-#
-# -zmagic:   
-#
-# LINKFLAGS    = -Ttext 0x100000
-#
-# -qmagic (we need to remove the 32 byte header for bootup purposes)
-#
-
-LINKFLAGS = -Ttext 0x1000
+LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
 
 CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- v2.1.36/linux/arch/m68k/amiga/amifb.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/amifb.c	Mon May 12 10:35:38 1997
@@ -50,12 +50,14 @@
 #include <linux/delay.h>
 #include <linux/config.h>
 #include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
-#include <linux/fb.h>
 
 #define DEBUG
 
@@ -1802,7 +1804,7 @@
 	 * Initialisation
 	 */
 
-struct fb_info *amiga_fb_init(long *mem_start)
+__initfunc(struct fb_info *amiga_fb_init(long *mem_start))
 {
 	int err, tag, i;
 	u_long chipptr;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v2.1.36/linux/arch/m68k/amiga/amiints.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/amiints.c	Mon May 12 10:35:38 1997
@@ -25,6 +25,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -68,7 +69,7 @@
  * the amiga IRQ handling routines.
  */
 
-void amiga_init_IRQ(void)
+__initfunc(void amiga_init_IRQ(void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- v2.1.36/linux/arch/m68k/amiga/amikeyb.c	Fri Dec 20 01:19:57 1996
+++ linux/arch/m68k/amiga/amikeyb.c	Mon May 12 10:35:38 1997
@@ -22,6 +22,7 @@
 #include <linux/kd.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
@@ -295,7 +296,7 @@
 	}
 }
 
-int amiga_keyb_init(void)
+__initfunc(int amiga_keyb_init(void))
 {
     if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
         return -EIO;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c
--- v2.1.36/linux/arch/m68k/amiga/amisound.c	Fri Dec 20 01:19:57 1996
+++ linux/arch/m68k/amiga/amisound.c	Mon May 12 10:35:38 1997
@@ -10,6 +10,7 @@
 
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/amigahw.h>
@@ -39,7 +40,7 @@
 
 static u_long clock_constant;
 
-static void init_sound(void)
+__initfunc(static void init_sound(void))
 {
 	snd_data = amiga_chip_alloc(sizeof(sine_data));
 	if (!snd_data) {
@@ -84,7 +85,7 @@
 		custom.aud[2].audlc = snd_data;
 		custom.aud[2].audlen = sizeof(sine_data)/2;
 		custom.aud[2].audper = (u_short)period;
-		custom.aud[2].audvol = 64; /* maxvol */
+		custom.aud[2].audvol = 32; /* 50% of maxvol */
 	
 		if (ticks) {
 			sound_timer.expires = jiffies + ticks;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c
--- v2.1.36/linux/arch/m68k/amiga/chipram.c	Fri Dec 20 01:19:57 1996
+++ linux/arch/m68k/amiga/chipram.c	Mon May 12 10:35:38 1997
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/amigahw.h>
 
 struct chip_desc {
@@ -21,19 +22,18 @@
 #define DP(ptr) ((struct chip_desc *)(ptr))
 
 u_long amiga_chip_size;
-static unsigned long chipavail; /*MILAN*/
+static unsigned long chipavail;
 
-/*MILAN*/
 unsigned long amiga_chip_avail( void )
 {
 #ifdef DEBUG
-   printk("chip_avail : %ld bytes\n",chipavail);
+	printk("chip_avail : %ld bytes\n",chipavail);
 #endif
-   return chipavail;
+	return chipavail;
 }
 
 
-void amiga_chip_init (void)
+__initfunc(void amiga_chip_init (void))
 {
   struct chip_desc *dp;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c
--- v2.1.36/linux/arch/m68k/amiga/cia.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/cia.c	Mon May 12 10:35:38 1997
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
+#include <linux/init.h>
 
 #include <asm/irq.h>
 #include <asm/amigahw.h>
@@ -152,7 +153,7 @@
 	amiga_do_irq_list(base->server_irq, fp, &base->server);
 }
 
-void cia_init_IRQ(struct ciabase *base)
+__initfunc(void cia_init_IRQ(struct ciabase *base))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.1.36/linux/arch/m68k/amiga/config.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/config.c	Mon May 12 10:35:38 1997
@@ -20,6 +20,7 @@
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/init.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -148,7 +149,7 @@
      *  Setup the Amiga configuration info
      */
 
-void config_amiga(void)
+__initfunc(void config_amiga(void))
 {
   /* Fill in some default values, if necessary */
   if (amiga_eclock == 0)
@@ -376,8 +377,8 @@
 
 static unsigned short jiffy_ticks;
 
-static void amiga_sched_init(void (*timer_routine)(int, void *,
-			     struct pt_regs *))
+__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
+					struct pt_regs *)))
 {
 	jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
@@ -796,7 +797,7 @@
 }
 #endif
 
-static void amiga_debug_init(void)
+__initfunc(static void amiga_debug_init(void))
 {
     if (!strcmp( m68k_debug_device, "ser" )) {
         /* no initialization required (?) */
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/cyberfb.c linux/arch/m68k/amiga/cyberfb.c
--- v2.1.36/linux/arch/m68k/amiga/cyberfb.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/cyberfb.c	Mon May 12 10:35:38 1997
@@ -29,12 +29,13 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/zorro.h>
+#include <linux/fb.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <linux/zorro.h>
 #include <asm/pgtable.h>
-#include <linux/fb.h>
 #include "s3blit.h"
 
 
@@ -1157,7 +1158,7 @@
     *    Initialization
     */
 
-struct fb_info *Cyber_fb_init(long *mem_start)
+__initfunc(struct fb_info *Cyber_fb_init(long *mem_start))
 {
    int err;
    struct Cyber_fb_par par;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/retz3fb.c linux/arch/m68k/amiga/retz3fb.c
--- v2.1.36/linux/arch/m68k/amiga/retz3fb.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/retz3fb.c	Mon May 12 10:35:38 1997
@@ -30,1762 +30,11 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
+#include <linux/zorro.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <linux/zorro.h>
-#include <asm/pgtable.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF  (4*1024*1024 - PAT_MEM_SIZE)
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
-
-struct retz3_fb_par {
-	int xres;
-	int yres;
-	int xres_vir;
-	int yres_vir;
-	int xoffset;
-	int yoffset;
-	int bpp;
-
-	struct fb_bitfield red;
-	struct fb_bitfield green;
-	struct fb_bitfield blue;
-	struct fb_bitfield transp;
-
-	int pixclock;
-	int left_margin;	/* time from sync to picture	*/
-	int right_margin;	/* time from picture to sync	*/
-	int upper_margin;	/* time from sync to picture	*/
-	int lower_margin;
-	int hsync_len;	/* length of horizontal sync	*/
-	int vsync_len;	/* length of vertical sync	*/
-	int vmode;
-};
-
-struct display_data {
-	long h_total;		/* Horizontal Total */
-	long h_sstart;		/* Horizontal Sync Start */
-	long h_sstop;		/* Horizontal Sync Stop */
-	long h_bstart;		/* Horizontal Blank Start */
-	long h_bstop;		/* Horizontal Blank Stop */
-	long h_dispend;		/* Horizontal Display End */
-	long v_total;		/* Vertical Total */
-	long v_sstart;		/* Vertical Sync Start */
-	long v_sstop;		/* Vertical Sync Stop */
-	long v_bstart;		/* Vertical Blank Start */
-	long v_bstop;		/* Vertical Blank Stop */
-	long v_dispend;		/* Horizontal Display End */
-};
-
-static struct retz3_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node;        /* node of the /dev/fb?current file */
-
-
-/*
- *    Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
-   /* Initialisation */
-
-   int (*init)(void);
-
-   /* Display Control */
-
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
-   int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
-		    int *green, unsigned int *blue, unsigned int *transp);
-   int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
-		    green, unsigned int blue, unsigned int transp);
-   void (*blank)(int blank);
-} *fbhw;
-
-
-/*
- *    Frame Buffer Name
- */
-
-static char retz3_fb_name[16] = "RetinaZ3";
-
-
-static int z3_key = 0;
-static unsigned char retz3_color_table [256][4];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-static long *memstart;
-
-
-/*
- *    Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
-	/*
-	 *    Autodetect (Default) Video Mode
-	 */
-
-	"default",
-
-	/*
-	 *    Predefined Video Modes
-	 */
-
-	"640x480",		/* RetinaZ3 8 bpp */
-	"800x600",		/* RetinaZ3 8 bpp */
-	"1024x768i",
-	"640x480-16",		/* RetinaZ3 16 bpp */
-	"640x480-24",		/* RetinaZ3 24 bpp */
-	
-	/*
-	 *    Dummy Video Modes
-	 */
-
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
-	/*
-	 *    User Defined Video Modes
-	 *
-	 *    This doesn't work yet!!
-	 */
-
-	"user0", "user1", "user2", "user3",
-	"user4", "user5", "user6", "user7"
-};
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600"     50      800  856  976 1040    600  637  643  666
- < name >     DCF       HR  SH1  SH2  HFL     VR  SV1  SV2  VFL
-
-The fields in the fb_var_screeninfo structure are:
-        unsigned long pixclock;         * pixel clock in ps (pico seconds) *
-        unsigned long left_margin;      * time from sync to picture    *
-        unsigned long right_margin;     * time from picture to sync    *
-        unsigned long upper_margin;     * time from sync to picture    *
-        unsigned long lower_margin;
-        unsigned long hsync_len;        * length of horizontal sync    *
-        unsigned long vsync_len;        * length of vertical sync      *
-
-1) Pixelclock:
-   xfree: in MHz
-   fb: In Picoseconds (ps)
-
-   pixclock = 1000000 / DCF
-
-2) horizontal timings:
-   left_margin = HFL - SH2
-   right_margin = SH1 - HR
-   hsync_len = SH2 - SH1
-
-3) vertical timings:
-   upper_margin = VFL - SV2
-   lower_margin = SV1 - VR
-   vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- *    Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   { 0, },
-
-   /*
-    *    Predefined Video Modes
-    */
-
-   /*
-    * NB: it is very important to adjust the pixel-clock to the color-depth.
-    */
-
-   {
-	   640, 480, 640, 480, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   /*
-    ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
-             < name > DCF HR  SH1 SH2  HFL VR  SV1 SV2 VFL
-    */
-   {
-	   /* 800 x 600, 8 bpp */
-	   800, 600, 800, 600, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
-	   FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   /*
-    ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
-              < name >   DCF HR  SH1  SH2  HFL  VR  SV1 SV2 VFL
-    */
-   {
-	   /* 1024 x 768, 8 bpp, interlaced */
-	   1024, 768, 1024, 768, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
-	   FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
-   },
-   {
-	   640, 480, 640, 480, 0, 0, 16, 0,
-	   {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   {
-	   640, 480, 640, 480, 0, 0, 24, 0,
-	   {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, 
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-
-   /*
-    *    Dummy Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, },
-
-   /*
-    *    User Defined Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES    arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES   (5)
-
-
-static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
-
-
-/*
- *    Interface used by the world
- */
-
-int retz3_probe(void);
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg, int con);
-
-
-/*
- *    Interface to the low level console driver
- */
-
-struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
-
-
-/*
- *    Accelerated Functions used by the low level console driver
- */
-
-void retz3_bitblt(struct fb_var_screeninfo *scr,
-		  unsigned short curx, unsigned short cury, unsigned
-		  short destx, unsigned short desty, unsigned short
-		  width, unsigned short height, unsigned short cmd,
-		  unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
-		width, unsigned short height, unsigned short mode,
-		unsigned short color);
-
-/*
- *   Hardware Specific Routines
- */
-
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3_fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
-                          struct retz3_fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
-                          struct retz3_fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
-			   unsigned int *green, unsigned int *blue,
-			   unsigned int *transp);
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue,
-			   unsigned int transp);
-static void retz3_blank(int blank);
-
-
-/*
- *    Internal routines
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void retz3_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
-	unsigned long f;
-	long tmp;
-	long prev = 0x7fffffff;
-	long n2, n1 = 3;
-	unsigned long m;
-	unsigned short res = 0;
-
-	if (freq <= 31250000)
-		n2 = 3;
-	else if (freq <= 62500000)
-		n2 = 2;
-	else if (freq <= 125000000)
-		n2 = 1;
-	else if (freq <= 250000000)
-		n2 = 0;
-	else
-		return(0);
-
-
-	do {
-		f = freq >> (10 - n2);
-
-		m = (f * n1) / (14318180/1024);
-
-		if (m > 129)
-			break;
-
-		tmp =  (((m * 14318180) >> n2) / n1) - freq;
-		if (tmp < 0)
-			tmp = -tmp;
-
-		if (tmp < prev) {
-			prev = tmp;
-			res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
-		}
-
-	} while ( (++n1) <= 21);
-
-	return res;
-}
-
-
-static int retz3_set_video(struct fb_var_screeninfo *var,
-			   struct retz3_fb_par *par)
-{
-	float freq_f;
-	long freq;
-
-	int xres, hfront, hsync, hback;
-	int yres, vfront, vsync, vback;
-	unsigned char tmp;
-	unsigned short best_freq;
-	struct display_data data;
-
-	short clocksel = 0; /* Apparantly this is always zero */
-
-	int bpp = var->bits_per_pixel;
-
-	/*
-	 * XXX
-	 */
-	if (bpp == 24)
-		return 0;
-
-	if ((bpp != 8) && (bpp != 16) && (bpp != 24))
-		return -EFAULT;
-
-	par->xoffset = 0;
-	par->yoffset = 0;
-
-	xres   = var->xres * bpp / 4;
-	hfront = var->right_margin * bpp / 4;
-	hsync  = var->hsync_len * bpp / 4;
-	hback  = var->left_margin * bpp / 4;
-
-	if (var->vmode & FB_VMODE_DOUBLE)
-	{
-		yres = var->yres * 2;
-		vfront = var->lower_margin * 2;
-		vsync  = var->vsync_len * 2;
-		vback  = var->upper_margin * 2;
-	}
-	else if (var->vmode & FB_VMODE_INTERLACED)
-	{
-		yres   = (var->yres + 1) / 2;
-		vfront = (var->lower_margin + 1) / 2;
-		vsync  = (var->vsync_len + 1) / 2;
-		vback  = (var->upper_margin + 1) / 2;
-	}
-	else
-	{
-		yres   = var->yres; /* -1 ? */
-		vfront = var->lower_margin;
-		vsync  = var->vsync_len;
-		vback  = var->upper_margin;
-	}
-
-	data.h_total	= (hback / 8) + (xres / 8) 
-			+ (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
-	data.h_dispend	= ((xres + bpp - 1)/ 8) - 1;
-	data.h_bstart	= xres / 8 /* + 1 */;
-
-	data.h_bstop	= data.h_total+1 + 2 + 1;
-	data.h_sstart	= (xres / 8) + (hfront / 8) + 1;
-	data.h_sstop	= (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
-	data.v_total	= yres + vfront + vsync + vback - 1;
-
-	data.v_dispend	= yres - 1;
-	data.v_bstart	= yres;
-
-	data.v_bstop	= data.v_total;
-	data.v_sstart	= yres + vfront - 1 - 2;
-	data.v_sstop	= yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
-	printk("HBS: %i\n", data.h_bstart);
-	printk("HSS: %i\n", data.h_sstart);
-	printk("HSE: %i\n", data.h_sstop);
-	printk("HBE: %i\n", data.h_bstop);
-	printk("HT: %i\n", data.h_total);
-
-	printk("hsync: %i\n", hsync);
-	printk("hfront: %i\n", hfront);
-	printk("hback: %i\n", hback);
-
-	printk("VBS: %i\n", data.v_bstart);
-	printk("VSS: %i\n", data.v_sstart);
-	printk("VSE: %i\n", data.v_sstop);
-	printk("VBE: %i\n", data.v_bstop);
-	printk("VT: %i\n", data.v_total);
-
-	printk("vsync: %i\n", vsync);
-	printk("vfront: %i\n", vfront);
-	printk("vback: %i\n", vback);
-#endif
-
-	if (data.v_total >= 1024)
-		printk("MAYDAY: v_total >= 1024; bailing out!\n");
-
-	reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
-	reg_w(GREG_FEATURE_CONTROL_W, 0x00);
-
-	seq_w(SEQ_RESET, 0x00);
-	seq_w(SEQ_RESET, 0x03);	/* reset sequencer logic */
-
-	/*
-	 * CLOCKING_MODE bits:
-	 * 2: This one is only set for certain text-modes, wonder if
-	 *    it may be for EGA-lines? (it was referred to as CLKDIV2)
-	 * (The CL drivers sets it to 0x21 with the comment:
-	 *  FullBandwidth (video off) and 8/9 dot clock)
-	 */
-	seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
-	seq_w(SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
-	seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
-	seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
-	seq_w(SEQ_RESET, 0x01);
-	seq_w(SEQ_RESET, 0x03);
-
-	seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
-	seq_w(SEQ_CURSOR_CONTROL, 0x00);	/* disable cursor */
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_LINEAR_0, 0x4a);
-	seq_w(SEQ_LINEAR_1, 0x00);
-
-	seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
-	seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
-	/*
-	 * The lower 4 bits (0-3) are used to set the font-width for
-	 * text-mode - DON'T try to set this for gfx-mode.
-	 */
-	seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
-	seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
-
-	/*
-	 * Extended Pixel Control:
-	 * bit 0:   text-mode=0, gfx-mode=1 (Graphics Byte ?)
-	 * bit 1: (Packed/Nibble Pixel Format ?)
-	 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
-	 */
-	seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
-	seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
-	seq_w(SEQ_COLOR_EXP_WFG, 0x01);
-	seq_w(SEQ_COLOR_EXP_WBG, 0x00);
-	seq_w(SEQ_EXT_RW_CONTROL, 0x00);
-	seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
-	seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
-	seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
-	seq_w(SEQ_CRC_CONTROL, 0x00);
-	seq_w(SEQ_PERF_SELECT, 0x10);
-	seq_w(SEQ_ACM_APERTURE_1, 0x00);
-	seq_w(SEQ_ACM_APERTURE_2, 0x30);
-	seq_w(SEQ_ACM_APERTURE_3, 0x00);
-	seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
-	/* unlock register CRT0..CRT7 */
-	crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
-	/* Zuerst zu schreibende Werte nur per printk ausgeben */
-	DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
-	crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
-
-	DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
-	crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
-	DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
-	crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
-	DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
-	crt_w(CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
-
-	DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
-	crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
-	tmp = (data.h_sstop & 0x1f);
-	if (data.h_bstop & 0x20)
-		tmp |= 0x80;
-	DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
-	crt_w(CRT_END_HOR_RETR, tmp);
-
-	DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
-	crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
-
-	tmp = 0x10;  /* LineCompare bit #9 */
-	if (data.v_total & 256)
-		tmp |= 0x01;
-	if (data.v_dispend & 256)
-		tmp |= 0x02;
-	if (data.v_sstart & 256)
-		tmp |= 0x04;
-	if (data.v_bstart & 256)
-		tmp |= 0x08;
-	if (data.v_total & 512)
-		tmp |= 0x20;
-	if (data.v_dispend & 512)
-		tmp |= 0x40;
-	if (data.v_sstart & 512)
-		tmp |= 0x80;
-	DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
-	crt_w(CRT_OVERFLOW, tmp);
-
-	crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
-	tmp = 0x40; /* LineCompare bit #8 */
-	if (data.v_bstart & 512)
-		tmp |= 0x20;
-	if (var->vmode & FB_VMODE_DOUBLE)
-		tmp |= 0x80;
- 	DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
-	crt_w(CRT_MAX_SCAN_LINE, tmp);
-
-	crt_w(CRT_CURSOR_START, 0x00);
-	crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
-	crt_w(CRT_START_ADDR_HIGH, 0x00);
-	crt_w(CRT_START_ADDR_LOW, 0x00);
-
-	crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
-	crt_w(CRT_CURSOR_LOC_LOW, 0x00);
-
- 	DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
-	crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
-	/* 5 refresh cycles per scanline */
-	DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
-	DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
-	DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
-	crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
-	DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
-	crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
-	DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
-	crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
-	DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
-	crt_w(CRT_MODE_CONTROL, 0xe3);
-
-	DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
-	crt_w(CRT_LINE_COMPARE, 0xff);
-
-	tmp = (var->xres_virtual / 8) * (bpp / 8);
-	crt_w(CRT_OFFSET, tmp);
-
-	crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
-	tmp = 0x20;			/* Enable extended end bits */
-	if (data.h_total & 0x100)
-		tmp |= 0x01;
-	if ((data.h_dispend) & 0x100)
-		tmp |= 0x02;
-	if (data.h_bstart & 0x100)
-		tmp |= 0x04;
-	if (data.h_sstart & 0x100)
-		tmp |= 0x08;
-	if (var->vmode & FB_VMODE_INTERLACED)
-		tmp |= 0x10;
- 	DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
-	crt_w(CRT_EXT_HOR_TIMING1, tmp);
-
-	tmp = 0x00;
-	if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
-		tmp |= 0x10;
-	crt_w(CRT_EXT_START_ADDR, tmp);
-
-	tmp = 0x00;
-	if (data.h_total & 0x200)
-		tmp |= 0x01;
-	if ((data.h_dispend) & 0x200)
-		tmp |= 0x02;
-	if (data.h_bstart & 0x200)
-		tmp |= 0x04;
-	if (data.h_sstart & 0x200)
-		tmp |= 0x08;
-	tmp |= ((data.h_bstop & 0xc0) >> 2);
-	tmp |= ((data.h_sstop & 0x60) << 1);
-	crt_w(CRT_EXT_HOR_TIMING2, tmp);
- 	DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
-	tmp = 0x10;			/* Line compare bit 10 */
-	if (data.v_total & 0x400)
-		tmp |= 0x01;
-	if ((data.v_dispend) & 0x400)
-		tmp |= 0x02;
-	if (data.v_bstart & 0x400)
-		tmp |= 0x04;
-	if (data.v_sstart & 0x400)
-		tmp |= 0x08;
-	tmp |= ((data.v_bstop & 0x300) >> 3);
-	if (data.v_sstop & 0x10)
-		tmp |= 0x80;
-	crt_w(CRT_EXT_VER_TIMING, tmp);
- 	DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
-	crt_w(CRT_MONITOR_POWER, 0x00);
-
-	/*
-	 * Convert from ps to Hz.
-	 */
-	freq_f = (1.0/(float)var->pixclock) * 1000000000;
-	freq = ((long)freq_f) * 1000;
-
-	best_freq = find_fq(freq);
-	pll_w(0x02, best_freq);
-	best_freq = find_fq(61000000);
-	pll_w(0x0a, best_freq);
-	pll_w(0x0e, 0x22);
-
-	gfx_w(GFX_SET_RESET, 0x00);
-	gfx_w(GFX_ENABLE_SET_RESET, 0x00);
-	gfx_w(GFX_COLOR_COMPARE, 0x00);
-	gfx_w(GFX_DATA_ROTATE, 0x00);
-	gfx_w(GFX_READ_MAP_SELECT, 0x00);
-	gfx_w(GFX_GRAPHICS_MODE, 0x00);
-	gfx_w(GFX_MISC, 0x05);
-	gfx_w(GFX_COLOR_XCARE, 0x0f);
-	gfx_w(GFX_BITMASK, 0xff);
-
-	reg_r(ACT_ADDRESS_RESET);
-	attr_w(ACT_PALETTE0 , 0x00);
-	attr_w(ACT_PALETTE1 , 0x01);
-	attr_w(ACT_PALETTE2 , 0x02);
-	attr_w(ACT_PALETTE3 , 0x03);
-	attr_w(ACT_PALETTE4 , 0x04);
-	attr_w(ACT_PALETTE5 , 0x05);
-	attr_w(ACT_PALETTE6 , 0x06);
-	attr_w(ACT_PALETTE7 , 0x07);
-	attr_w(ACT_PALETTE8 , 0x08);
-	attr_w(ACT_PALETTE9 , 0x09);
-	attr_w(ACT_PALETTE10, 0x0a);
-	attr_w(ACT_PALETTE11, 0x0b);
-	attr_w(ACT_PALETTE12, 0x0c);
-	attr_w(ACT_PALETTE13, 0x0d);
-	attr_w(ACT_PALETTE14, 0x0e);
-	attr_w(ACT_PALETTE15, 0x0f);
-	reg_r(ACT_ADDRESS_RESET);
-
-	attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
-	attr_w(ACT_OVERSCAN_COLOR, 0x00);
-	attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
-	attr_w(ACT_HOR_PEL_PANNING, 0x00);
-	attr_w(ACT_COLOR_SELECT, 0x00);
-
-	reg_r(ACT_ADDRESS_RESET);
-	reg_w(ACT_DATA, 0x20);
-
-	reg_w(VDAC_MASK, 0xff);
-
-	/*
-	 * Extended palette adressing ???
-	 */
-	switch (bpp){
-	case 8:
-		reg_w(0x83c6, 0x00); 
-		break;
-	case 16:
-		reg_w(0x83c6, 0x60);
-		break;
-	case 24:
-		reg_w(0x83c6, 0xe0);
-		break;
-	default:
-		printk("Illegal color-depth: %i\n", bpp);
-	}
-
-	reg_w(VDAC_ADDRESS, 0x00);
-
-	seq_w(SEQ_MAP_MASK, 0x0f );  
-
-	return 0;
-}
-
-/*
- *    Initialization
- *
- *    Set the default video mode for this chipset. If a video mode was
- *    specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
-	int i;
-#if 0
-	volatile unsigned long *CursorBase;
-#endif
-	unsigned long board_addr, board_size;
-	struct ConfigDev *cd;
-
-	cd = zorro_get_board (z3_key);
-	zorro_config_board (z3_key, 0);
-	board_addr = (unsigned long)cd->cd_BoardAddr;
-	board_size = (unsigned long)cd->cd_BoardSize;
-
-	for (i = 0; i < 256; i++){
-		for (i = 0; i < 256; i++){
-			retz3_color_table [i][0] = i;
-			retz3_color_table [i][1] = i;
-			retz3_color_table [i][2] = i;
-			retz3_color_table [i][3] = 0;
-		}
-	}
-
-	*memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-	z3_mem = kernel_map (board_addr, board_size,
-			     KERNELMAP_NOCACHE_SER, memstart);
-
-	z3_regs = (char*) z3_mem;
-	z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
-	/* Get memory size - for now we asume its a 4MB board */
-
-	z3_size = 0x00400000; /* 4 MB */
-
-	memset ((char*)z3_fbmem, 0, z3_size);
-
-	/* Disable hardware cursor */
-
-	seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-
-#if 0
-	/* Initialize hardware cursor */
-	CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
-	for (i=0; i < 8; i++){
-		*(CursorBase  +(i*4)) = 0xffffff00;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-	for (i=8; i < 64; i++){
-		*(CursorBase  +(i*4)) = 0xffff0000;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-#endif
-
-	retz3_setcolreg (255, 56, 100, 160, 0);
-	retz3_setcolreg (254, 0, 0, 0, 0);
-
-	return 0;
-}
-
-
-/*
- *    This function should fill in the `fix' structure based on the
- *    values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3_fb_par *par)
-{
-	int i;
-
-	strcpy(fix->id, retz3_fb_name);
-	fix->smem_start = z3_fbmem;
-	fix->smem_len = z3_size;
-
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux = 0;
-	if (par->bpp == 8)
-		fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	else
-		fix->visual = FB_VISUAL_DIRECTCOLOR;
-
-	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;
-}
-
-
-/*
- *    Get the video params out of `var'. If a value doesn't fit, round
- *    it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
-			    struct retz3_fb_par *par)
-{
-	par->xres = var->xres;
-	par->yres = var->yres;
-	par->xres_vir = var->xres_virtual;
-	par->yres_vir = var->yres_virtual;
-	par->bpp = var->bits_per_pixel;
-	par->pixclock = var->pixclock;
-	par->vmode = var->vmode;
-
-	par->red = var->red;
-	par->green = var->green;
-	par->blue = var->blue;
-	par->transp = var->transp;
-
-	par->left_margin = var->left_margin;
-	par->right_margin = var->right_margin;
-	par->upper_margin = var->upper_margin;
-	par->lower_margin = var->lower_margin;
-	par->hsync_len = var->hsync_len;
-	par->vsync_len = var->vsync_len;
-
-	return 0;
-}
-
-
-/*
- *    Fill the `var' structure based on the values in `par' and maybe
- *    other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
-			    struct retz3_fb_par *par)
-{
-	int i;
-
-	var->xres = par->xres;
-	var->yres = par->yres;
-	var->xres_virtual = par->xres_vir;
-	var->yres_virtual = par->yres_vir;
-	var->xoffset = 0;
-	var->yoffset = 0;
-
-	var->bits_per_pixel = par->bpp;
-	var->grayscale = 0;
-
-	var->red = par->red;
-	var->green = par->green;
-	var->blue = par->blue;
-	var->transp = par->transp;
-
-	var->nonstd = 0;
-	var->activate = 0;
-
-	var->height = -1;
-	var->width = -1;
-
-	var->accel = FB_ACCEL_RETINAZ3;
-
-	var->pixclock = par->pixclock;
-
-	var->sync = 0;				/* ??? */
-	var->left_margin = par->left_margin;
-	var->right_margin = par->right_margin;
-	var->upper_margin = par->upper_margin;
-	var->lower_margin = par->lower_margin;
-	var->hsync_len = par->hsync_len;
-	var->vsync_len = par->vsync_len;
-
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-
-	var->vmode = par->vmode;
-	return 0;
-}
-
-
-/*
- *    Set a single color register. The values supplied are already
- *    rounded down to the hardware's capabilities (according to the
- *    entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue,
-			   unsigned int transp)
-{
-	/* We'll get to this */
-
-	if (regno > 255)
-		return 1;
-
-	retz3_color_table [regno][0] = red & 0xff;
-	retz3_color_table [regno][1] = green & 0xff;
-	retz3_color_table [regno][2] = blue & 0xff;
-	retz3_color_table [regno][3] = transp;
-
-	reg_w(VDAC_ADDRESS_W, regno);
-	reg_w(VDAC_DATA, (red & 0xff) >> 2);
-	reg_w(VDAC_DATA, (green & 0xff) >> 2);
-	reg_w(VDAC_DATA, (blue & 0xff) >> 2);
-
-	return 0;
-}
-
-
-/*
- *    Read a single color register and split it into
- *    colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
-			   unsigned int *green, unsigned int *blue,
-			   unsigned int *transp)
-{
-	if (regno > 255)
-		return 1;
-	*red    = retz3_color_table [regno][0];
-	*green  = retz3_color_table [regno][1];
-	*blue   = retz3_color_table [regno][2];
-	*transp = retz3_color_table [regno][3];
-	return 0;
-}
-
-
-/*
- *    (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
-	int i;
-
-	if (blank)
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-		}
-	else
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
-			reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
-			reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
-		}
-}
-
-
-void retz3_bitblt (struct fb_var_screeninfo *var,
-		   unsigned short srcx, unsigned short srcy, unsigned
-		   short destx, unsigned short desty, unsigned short
-		   width, unsigned short height, unsigned short cmd,
-		   unsigned short mask)
-{
-
-	volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
-	unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
-
-	unsigned short mod;
-	unsigned long tmp;
-	unsigned long pat, src, dst;
-	unsigned char blt_status;
-
-	int i, xres_virtual = var->xres_virtual;
-	short bpp = (var->bits_per_pixel & 0xff);
-
-	if (bpp < 8)
-		bpp = 8;
-
-	tmp = mask | (mask << 16);
-
-#if 0
-	/*
-	 * Check for blitter finished before we start messing with the
-	 * pattern.
-	 */
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}while ((blt_status & 1) == 0);
-#endif
-
-	i = 0;
-	do{
-		*pattern++ = tmp;
-	}while(i++ < bpp/4);
-
-	tmp = cmd << 8;
-	*(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
-	mod = 0xc0c2;
-
-	pat = 8 * PAT_MEM_OFF;
-	dst = bpp * (destx + desty * xres_virtual);
-
-	/*
-	 * Source is not set for clear.
-	 */
-	if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
-		src = bpp * (srcx + srcy * xres_virtual);
-
-		if (destx > srcx) {
-			mod &= ~0x8000;
-			src += bpp * (width - 1);
-			dst += bpp * (width - 1);
-			pat += bpp * 2;
-		}
-		if (desty > srcy) {
-			mod &= ~0x4000;
-			src += bpp * (height - 1) * xres_virtual;
-			dst += bpp * (height - 1) * xres_virtual;
-			pat += bpp * 4;
-		}
-
-		*(acm + ACM_SOURCE/4) = cpu_to_le32(src);
-	}
-
-	*(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
-	*(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
-	tmp = mod << 16;
-	*(acm + ACM_CONTROL/4) = tmp;
-
-	tmp  = width | (height << 16);
-	
-	*(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
-	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
-	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
-	/*
-	 * No reason to wait for the blitter to finish, it is better
-	 * just to check if it has finished before we use it again.
-	 */
-#if 1
-#if 0
-	while ((*(((volatile unsigned char *)acm) +
-		  (ACM_START_STATUS + 2)) & 1) == 0);
-#else
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}
-	while ((blt_status & 1) == 0);
-#endif
-#endif
-}
-
-#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
-		 short width, unsigned short height,
-		 unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
-	/* Guess we gotta deal with the cursor at some point */
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
-	retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
-	retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- *    Fill the hardware's `par' structure.
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par)
-{
-	if (current_par_valid)
-		*par = current_par;
-	else
-		fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
-}
-
-
-static void retz3_fb_set_par(struct retz3_fb_par *par)
-{
-	current_par = *par;
-	current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-	int err, activate;
-	struct retz3_fb_par par;
-
-	if ((err = fbhw->decode_var(var, &par)))
-		return err;
-	activate = var->activate;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-		retz3_fb_set_par(&par);
-	fbhw->encode_var(var, &par);
-	var->activate = activate;
-
-#if 1
-	retz3_set_video(var, &current_par);
-#endif
-	return 0;
-}
-
-
-/*
- *    Default Colormaps
- */
-
-static unsigned short red16[] =
-	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static unsigned short green16[] =
-	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static unsigned short blue16[] =
-	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
-	  0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_16_colors =
-   { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
-	return &default_16_colors;
-}
-
-
-#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
-                                              ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
-			return 0;
-		hred = CNVT_FROMHW(hred, var->red.length);
-		hgreen = CNVT_FROMHW(hgreen, var->green.length);
-		hblue = CNVT_FROMHW(hblue, var->blue.length);
-		htransp = CNVT_FROMHW(htransp, var->transp.length);
-		if (kspc) {
-			*red = hred;
-			*green = hgreen;
-			*blue = hblue;
-			if (transp)
-				*transp = htransp;
-		} else {
-			put_user(hred, red);
-			put_user(hgreen, green);
-			put_user(hblue, blue);
-			if (transp)
-				put_user(htransp, transp);
-		}
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-	}
-	return 0;
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (kspc) {
-			hred = *red;
-			hgreen = *green;
-			hblue = *blue;
-			htransp = transp ? *transp : 0;
-		} else {
-			get_user(hred, red);
-			get_user(hgreen, green);
-			get_user(hblue, blue);
-			if (transp)
-				get_user(htransp, transp);
-			else
-				htransp = 0;
-		}
-		hred = CNVT_TOHW(hred, var->red.length);
-		hgreen = CNVT_TOHW(hgreen, var->green.length);
-		hblue = CNVT_TOHW(hblue, var->blue.length);
-		htransp = CNVT_TOHW(htransp, var->transp.length);
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-		if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
-			return 0;
-	}
-	return 0;
-}
-
-
-static void do_install_cmap(int con)
-{
-	if (con != currcon)
-		return;
-	if (disp[con].cmap.len)
-		do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
-	else
-		do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-                                          &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-	switch (fsfromto) {
-	case 0:
-		memcpy(to, from, len);
-		return;
-	case 1:
-		copy_from_user(to, from, len);
-		return;
-	case 2:
-		copy_to_user(to, from, len);
-		return;
-	}
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-	int size;
-	int tooff = 0, fromoff = 0;
-
-	if (to->start > from->start)
-		fromoff = to->start-from->start;
-	else
-		tooff = from->start-to->start;
-	size = to->len-tooff;
-	if (size > from->len-fromoff)
-		size = from->len-fromoff;
-	if (size < 0)
-		return;
-	size *= sizeof(unsigned short);
-	memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-	memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-	memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-	if (from->transp && to->transp)
-		memcpy_fs(fsfromto, to->transp+tooff,
-			  from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-	int size = len*sizeof(unsigned short);
-
-	if (cmap->len != len) {
-		if (cmap->red)
-			kfree(cmap->red);
-		if (cmap->green)
-			kfree(cmap->green);
-		if (cmap->blue)
-			kfree(cmap->blue);
-		if (cmap->transp)
-			kfree(cmap->transp);
-		cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-		cmap->len = 0;
-		if (!len)
-			return 0;
-		if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (transp) {
-			if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
-				return -1;
-		} else
-			cmap->transp = NULL;
-	}
-	cmap->start = 0;
-	cmap->len = len;
-	copy_cmap(get_default_colormap(len), cmap, 0);
-	return 0;
-}
-
-
-/*
- *    Get the Fixed Part of the Display
- */
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-	struct retz3_fb_par par;
-	int error = 0;
-
-	if (con == -1)
-		retz3_fb_get_par(&par);
-	else
-		error = fbhw->decode_var(&disp[con].var, &par);
-	return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-/*
- *    Get the User Defined Part of the Display
- */
-
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-	struct retz3_fb_par par;
-	int error = 0;
-
-	if (con == -1) {
-		retz3_fb_get_par(&par);
-		error = fbhw->encode_var(var, &par);
-	} else
-		*var = disp[con].var;
-	return error;
-}
-
-
-static void retz3_fb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-
-	retz3_fb_get_fix(&fix, con);
-	if (con == -1)
-		con = 0;
-	disp[con].screen_base = (unsigned char *)fix.smem_start;
-	disp[con].visual = fix.visual;
-	disp[con].type = fix.type;
-	disp[con].type_aux = fix.type_aux;
-	disp[con].ypanstep = fix.ypanstep;
-	disp[con].ywrapstep = fix.ywrapstep;
-	disp[con].can_soft_blank = 1;
-	disp[con].inverse = z3fb_inverse;
-}
-
-
-/*
- *    Set the User Defined Part of the Display
- */
-
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
-	if ((err = do_fb_set_var(var, con == currcon)))
-		return err;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = disp[con].var.xres;
-		oldyres = disp[con].var.yres;
-		oldvxres = disp[con].var.xres_virtual;
-		oldvyres = disp[con].var.yres_virtual;
-		oldbpp = disp[con].var.bits_per_pixel;
-		disp[con].var = *var;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual ||
-		    oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-			retz3_fb_set_disp(con);
-			(*fb_info.changevar)(con);
-			alloc_cmap(&disp[con].cmap, 0, 0);
-			do_install_cmap(con);
-		}
-	}
-	var->activate = 0;
-	return 0;
-}
-
-
-/*
- *    Get the Colormap
- */
-
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	if (con == currcon) /* current console? */
-		return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
-	else if (disp[con].cmap.len) /* non default colormap? */
-		copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-			  cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-
-/*
- *    Set the Colormap
- */
-
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	int err;
-
-	if (!disp[con].cmap.len) {       /* no colormap allocated? */
-		if ((err = alloc_cmap(&disp[con].cmap,
-				      1<<disp[con].var.bits_per_pixel, 0)))
-			return err;
-	}
-	if (con == currcon)              /* current console? */
-		return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
-	else
-		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-	return 0;
-}
-
-
-/*
- *    Pan or Wrap the Display
- *
- *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
-	return -EINVAL;
-}
-
-
-/*
- *    RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg, int con)
-{
-	return -EINVAL;
-}
-
-
-static struct fb_ops retz3_fb_ops = {
-   retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
-   retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
-};
-
-
-int retz3_probe(void)
-{
-	z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
-	return(z3_key);
-}
-
-
-void retz3_video_setup(char *options, int *ints)
-{
-	char *this_opt;
-	int i;
-
-	fb_info.fontname[0] = '\0';
-
-	if (!options || !*options)
-		return;
-
-	for (this_opt = strtok(options, ","); this_opt; 
-	     this_opt = strtok(NULL, ",")){
-		if (!strcmp(this_opt, "inverse")) {
-			z3fb_inverse = 1;
-			for (i = 0; i < 16; i++) {
-				red16[i] = ~red16[i];
-				green16[i] = ~green16[i];
-				blue16[i] = ~blue16[i];
-			}
-		} else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
-		else
-			z3fb_mode = get_video_mode(this_opt);
-	}
-}
-
-
-/*
- *    Initialization
- */
-
-struct fb_info *retz3_fb_init(long *mem_start)
-{
-	int err;
-	struct retz3_fb_par par;
-
-	memstart = mem_start;
-
-	fbhw = &retz3_switch;
-
-	err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
-				   NUM_TOTAL_MODES, retz3_fb_predefined);
-	if (err < 0)
-		panic("Cannot register frame buffer\n");
-
-	fbhw->init();
-
-	if (z3fb_mode == -1)
-		z3fb_mode = 1;
-
-	fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
-	fbhw->encode_var(&retz3_fb_predefined[0], &par);
-
-	strcpy(fb_info.modename, retz3_fb_name);
-	fb_info.disp = disp;
-	fb_info.switch_con = &z3fb_switch;
-	fb_info.updatevar = &z3fb_updatevar;
-	fb_info.blank = &z3fb_blank;
-	fb_info.setcmap = &z3fb_setcmap;
-
-	do_fb_set_var(&retz3_fb_predefined[0], 0);
-	retz3_fb_get_var(&disp[0].var, -1);
-	retz3_fb_set_disp(-1);
-	do_install_cmap(0);
-
-	return &fb_info;
-}
-
-
-static int z3fb_switch(int con)
-{
-	/* Do we have to save the colormap? */
-	if (disp[currcon].cmap.len)
-		do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
-	do_fb_set_var(&disp[con].var, 1);
-	currcon = con;
-	/* Install new colormap */
-	do_install_cmap(con);
-	return 0;
-}
-
-
-/*
- *    Update the `var' structure (called by fbcon.c)
- *
- *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- *    Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con)
-{
-	return 0;
-}
-
-
-/*
- *    Blank the display.
- */
-
-static void z3fb_blank(int blank)
-{
-	fbhw->blank(blank);
-}
-
-
-/*
- *    Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
-	return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
- *    Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
-	int i;
-
-	for (i = 1; i <= NUM_PREDEF_MODES; i++)
-		if (!strcmp(name, retz3_fb_modenames[i])){
-			retz3_fb_predefined[0] = retz3_fb_predefined[i];
-			return i;
-		}
-	return -1;
-}
-/*
- * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
- *                                    RetinaZ3 frame buffer device
- *
- *    Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- *                               Geert Uytterhoeven
- * clgen.c:   Copyright (C) 1996 Frank Neumann
- *
- * History:
- *   - 22 Jan 97: Initial work
- *   - 14 Feb 97: Screen initialization works somewhat, still only
- *                8-bit packed pixel is supported.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <linux/zorro.h>
 #include <asm/pgtable.h>
 
 #include "retz3fb.h"
@@ -3402,7 +1651,7 @@
  *    Initialization
  */
 
-struct fb_info *retz3_fb_init(long *mem_start)
+__initfunc(struct fb_info *retz3_fb_init(long *mem_start))
 {
 	int err;
 	struct retz3_fb_par par;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/retz3fb.h linux/arch/m68k/amiga/retz3fb.h
--- v2.1.36/linux/arch/m68k/amiga/retz3fb.h	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/retz3fb.h	Mon May 12 10:35:38 1997
@@ -284,289 +284,3 @@
 #define Z3BLTorInverted		0xb0	/* NOT src OR dst */
 #define Z3BLTnand		0x70	/* NOT src OR NOT dst */
 #define Z3BLTset		0xf0	/* 1 */
-/*
- * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the
- *                                    RetinaZ3 frame buffer device
- *
- *    Copyright (C) 1997 Jes Sorensen
- *
- * History:
- *   - 22 Jan 97: Initial work
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(sreg,sdat) \
-	do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(creg,cdat) \
-	do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(greg,gdat) \
-	do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(areg,adat) \
-	do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(preg,pdat) \
-	do{ reg_w(PLL_IDX, preg); \
-	    reg_w(PLL_DATA, (pdat & 0xff)); \
-	    reg_w(PLL_DATA, (pdat >> 8));\
-	} while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET	0x00c00000
-#define ACM_OFFSET		0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET	0x00
-#define ACM_SECONDARY_OFFSET	0x04
-#define ACM_MODE_CONTROL	0x08
-#define ACM_CURSOR_POSITION	0x0c
-#define ACM_START_STATUS	0x30
-#define ACM_CONTROL		0x34
-#define ACM_RASTEROP_ROTATION	0x38
-#define ACM_BITMAP_DIMENSION	0x3c
-#define ACM_DESTINATION		0x40
-#define ACM_SOURCE		0x44
-#define ACM_PATTERN		0x48
-#define ACM_FOREGROUND		0x4c
-#define ACM_BACKGROUND		0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS		0x03c8
-#define VDAC_ADDRESS_W		0x03c8
-#define VDAC_ADDRESS_R		0x03c7
-#define VDAC_STATE		0x03c7
-#define VDAC_DATA		0x03c9
-#define VDAC_MASK		0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX			0x03c4	/* Sequencer Index */
-#define SEQ_DATA		0x03c5
-#define SEQ_RESET		0x00
-#define SEQ_CLOCKING_MODE	0x01
-#define SEQ_MAP_MASK		0x02
-#define SEQ_CHAR_MAP_SELECT	0x03
-#define SEQ_MEMORY_MODE		0x04
-#define SEQ_EXTENDED_ENABLE	0x05	/* NCR extensions */
-#define SEQ_UNKNOWN1         	0x06
-#define SEQ_UNKNOWN2         	0x07
-#define SEQ_CHIP_ID		0x08
-#define SEQ_UNKNOWN3         	0x09
-#define SEQ_CURSOR_COLOR1	0x0a
-#define SEQ_CURSOR_COLOR0	0x0b
-#define SEQ_CURSOR_CONTROL	0x0c
-#define SEQ_CURSOR_X_LOC_HI	0x0d
-#define SEQ_CURSOR_X_LOC_LO	0x0e
-#define SEQ_CURSOR_Y_LOC_HI	0x0f
-#define SEQ_CURSOR_Y_LOC_LO	0x10
-#define SEQ_CURSOR_X_INDEX	0x11
-#define SEQ_CURSOR_Y_INDEX	0x12
-#define SEQ_CURSOR_STORE_HI	0x13
-#define SEQ_CURSOR_STORE_LO	0x14
-#define SEQ_CURSOR_ST_OFF_HI	0x15
-#define SEQ_CURSOR_ST_OFF_LO	0x16
-#define SEQ_CURSOR_PIXELMASK	0x17
-#define SEQ_PRIM_HOST_OFF_HI	0x18
-#define SEQ_PRIM_HOST_OFF_LO	0x19
-#define SEQ_LINEAR_0		0x1a
-#define SEQ_LINEAR_1		0x1b
-#define SEQ_SEC_HOST_OFF_HI	0x1c
-#define SEQ_SEC_HOST_OFF_LO	0x1d
-#define SEQ_EXTENDED_MEM_ENA	0x1e
-#define SEQ_EXT_CLOCK_MODE	0x1f
-#define SEQ_EXT_VIDEO_ADDR	0x20
-#define SEQ_EXT_PIXEL_CNTL	0x21
-#define SEQ_BUS_WIDTH_FEEDB	0x22
-#define SEQ_PERF_SELECT		0x23
-#define SEQ_COLOR_EXP_WFG	0x24
-#define SEQ_COLOR_EXP_WBG	0x25
-#define SEQ_EXT_RW_CONTROL	0x26
-#define SEQ_MISC_FEATURE_SEL	0x27
-#define SEQ_COLOR_KEY_CNTL	0x28
-#define SEQ_COLOR_KEY_MATCH0	0x29
-#define SEQ_COLOR_KEY_MATCH1 	0x2a
-#define SEQ_COLOR_KEY_MATCH2 	0x2b
-#define SEQ_UNKNOWN6         	0x2c
-#define SEQ_CRC_CONTROL		0x2d
-#define SEQ_CRC_DATA_LOW	0x2e
-#define SEQ_CRC_DATA_HIGH	0x2f
-#define SEQ_MEMORY_MAP_CNTL	0x30
-#define SEQ_ACM_APERTURE_1	0x31
-#define SEQ_ACM_APERTURE_2	0x32
-#define SEQ_ACM_APERTURE_3	0x33
-#define SEQ_BIOS_UTILITY_0	0x3e
-#define SEQ_BIOS_UTILITY_1	0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX			0x03ce
-#define GFX_DATA		0x03cf
-#define GFX_SET_RESET		0x00
-#define GFX_ENABLE_SET_RESET	0x01
-#define GFX_COLOR_COMPARE	0x02
-#define GFX_DATA_ROTATE		0x03
-#define GFX_READ_MAP_SELECT	0x04
-#define GFX_GRAPHICS_MODE	0x05
-#define GFX_MISC		0x06
-#define GFX_COLOR_XCARE		0x07
-#define GFX_BITMASK		0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX			0x03d4
-#define CRT_DATA		0x03d5
-#define CRT_HOR_TOTAL		0x00
-#define CRT_HOR_DISP_ENA_END	0x01
-#define CRT_START_HOR_BLANK	0x02
-#define CRT_END_HOR_BLANK	0x03
-#define CRT_START_HOR_RETR	0x04
-#define CRT_END_HOR_RETR	0x05
-#define CRT_VER_TOTAL		0x06
-#define CRT_OVERFLOW		0x07
-#define CRT_PRESET_ROW_SCAN	0x08
-#define CRT_MAX_SCAN_LINE	0x09
-#define CRT_CURSOR_START	0x0a
-#define CRT_CURSOR_END		0x0b
-#define CRT_START_ADDR_HIGH	0x0c
-#define CRT_START_ADDR_LOW	0x0d
-#define CRT_CURSOR_LOC_HIGH	0x0e
-#define CRT_CURSOR_LOC_LOW	0x0f
-#define CRT_START_VER_RETR	0x10
-#define CRT_END_VER_RETR	0x11
-#define CRT_VER_DISP_ENA_END	0x12
-#define CRT_OFFSET		0x13
-#define CRT_UNDERLINE_LOC	0x14
-#define CRT_START_VER_BLANK	0x15
-#define CRT_END_VER_BLANK	0x16
-#define CRT_MODE_CONTROL	0x17
-#define CRT_LINE_COMPARE	0x18
-#define CRT_UNKNOWN1         	0x19
-#define CRT_UNKNOWN2         	0x1a
-#define CRT_UNKNOWN3         	0x1b
-#define CRT_UNKNOWN4         	0x1c
-#define CRT_UNKNOWN5         	0x1d
-#define CRT_UNKNOWN6         	0x1e
-#define CRT_UNKNOWN7         	0x1f
-#define CRT_UNKNOWN8         	0x20
-#define CRT_UNKNOWN9		0x21
-#define CRT_UNKNOWN10		0x22
-#define CRT_UNKNOWN11      	0x23
-#define CRT_UNKNOWN12      	0x24
-#define CRT_UNKNOWN13      	0x25
-#define CRT_UNKNOWN14      	0x26
-#define CRT_UNKNOWN15      	0x27
-#define CRT_UNKNOWN16      	0x28
-#define CRT_UNKNOWN17      	0x29
-#define CRT_UNKNOWN18      	0x2a
-#define CRT_UNKNOWN19      	0x2b
-#define CRT_UNKNOWN20      	0x2c
-#define CRT_UNKNOWN21      	0x2d
-#define CRT_UNKNOWN22      	0x2e
-#define CRT_UNKNOWN23      	0x2f
-#define CRT_EXT_HOR_TIMING1	0x30	/* NCR crt extensions */
-#define CRT_EXT_START_ADDR	0x31
-#define CRT_EXT_HOR_TIMING2	0x32
-#define CRT_EXT_VER_TIMING	0x33
-#define CRT_MONITOR_POWER	0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R		0x03c2
-#define GREG_STATUS1_R		0x03da
-#define GREG_MISC_OUTPUT_R	0x03cc
-#define GREG_MISC_OUTPUT_W	0x03c2	
-#define GREG_FEATURE_CONTROL_R	0x03ca
-#define GREG_FEATURE_CONTROL_W	0x03da
-#define GREG_POS		0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX			0x03C0
-#define ACT_ADDRESS_R		0x03C0
-#define ACT_DATA		0x03C0
-#define ACT_ADDRESS_RESET	0x03DA
-#define ACT_PALETTE0		0x00
-#define ACT_PALETTE1		0x01
-#define ACT_PALETTE2		0x02
-#define ACT_PALETTE3		0x03
-#define ACT_PALETTE4		0x04
-#define ACT_PALETTE5		0x05
-#define ACT_PALETTE6		0x06
-#define ACT_PALETTE7		0x07
-#define ACT_PALETTE8		0x08
-#define ACT_PALETTE9		0x09
-#define ACT_PALETTE10		0x0A
-#define ACT_PALETTE11		0x0B
-#define ACT_PALETTE12		0x0C
-#define ACT_PALETTE13		0x0D
-#define ACT_PALETTE14		0x0E
-#define ACT_PALETTE15		0x0F
-#define ACT_ATTR_MODE_CNTL	0x10
-#define ACT_OVERSCAN_COLOR	0x11
-#define ACT_COLOR_PLANE_ENA	0x12
-#define ACT_HOR_PEL_PANNING	0x13
-#define ACT_COLOR_SELECT	0x14
-
-/*
- * PLL
- */
-#define PLL_IDX			0x83c8
-#define PLL_DATA		0x83c9
-
-/*
- * Blitter operations
- */
-#define	Z3BLTclear		0x00	/* 0 */
-#define Z3BLTand		0x80	/* src AND dst */
-#define Z3BLTandReverse		0x40	/* src AND NOT dst */
-#define Z3BLTcopy		0xc0	/* src */
-#define Z3BLTandInverted	0x20	/* NOT src AND dst */
-#define	Z3BLTnoop		0xa0	/* dst */
-#define Z3BLTxor		0x60	/* src XOR dst */
-#define Z3BLTor			0xe0	/* src OR dst */
-#define Z3BLTnor		0x10	/* NOT src AND NOT dst */
-#define Z3BLTequiv		0x90	/* NOT src XOR dst */
-#define Z3BLTinvert		0x50	/* NOT dst */
-#define Z3BLTorReverse		0xd0	/* src OR NOT dst */
-#define Z3BLTcopyInverted	0x30	/* NOT src */
-#define Z3BLTorInverted		0xb0	/* NOT src OR dst */
-#define Z3BLTnand		0x70	/* NOT src OR NOT dst */
-#define Z3BLTset		0xf0	/* 1 */
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- v2.1.36/linux/arch/m68k/amiga/zorro.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/amiga/zorro.c	Mon May 12 10:35:38 1997
@@ -13,10 +13,11 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
 #include <asm/setup.h>
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
-#include <linux/zorro.h>
 
 
 #ifdef CONFIG_ZORRO
@@ -415,10 +416,6 @@
    PROD("MVD 819", MVD_819)
 END
 
-BEGIN_PROD(DELACOMP)
-   PROD("RAM Expansion 2000", DELACOMP_RAM_2000)
-END
-
 BEGIN_PROD(VILLAGE_TRONIC)
    PROD("Domino Graphics Board (RAM)", DOMINO_RAM)
    PROD("Domino Graphics Board (REG)", DOMINO_REG)
@@ -656,7 +653,6 @@
    MANUF("Helfrich", HELFRICH1)
    MANUF("Software Result Enterprises", SW_RESULT_ENTS)
    MANUF("Masoboshi", MASOBOSHI)
-   MANUF("DelaComp", DELACOMP)
    MANUF("Village Tronic", VILLAGE_TRONIC)
    MANUF("Utilities Unlimited", UTILITIES_ULTD)
    MANUF("Amitrix", AMITRIX)
@@ -992,7 +988,7 @@
     *    Initialization
     */
 
-void zorro_init(void)
+__initfunc(void zorro_init(void))
 {
    int i;
    struct ConfigDev *cd;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- v2.1.36/linux/arch/m68k/atari/atafb.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/atafb.c	Mon May 12 10:35:38 1997
@@ -46,6 +46,7 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -2911,8 +2912,8 @@
 	return(atari_fb_set_cmap(cmap, 1, con));
 }
 
-struct fb_info *
-atari_fb_init(long *mem_start)
+__initfunc(struct fb_info *
+atari_fb_init(long *mem_start))
 {
 	int err;
 	int pad;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v2.1.36/linux/arch/m68k/atari/ataints.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/ataints.c	Mon May 12 10:35:38 1997
@@ -39,6 +39,7 @@
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
 #include <linux/kernel_stat.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/traps.h>
@@ -331,7 +332,7 @@
  * the atari IRQ handling routines.
  */
 
-void atari_init_IRQ(void)
+__initfunc(void atari_init_IRQ(void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.1.36/linux/arch/m68k/atari/atakeyb.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/atakeyb.c	Mon May 12 10:35:38 1997
@@ -22,6 +22,7 @@
 #include <linux/timer.h>
 #include <linux/kd.h>
 #include <linux/random.h>
+#include <linux/init.h>
 
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
@@ -804,7 +805,7 @@
  * Martin Rogge, 20 Aug 1995
  */
  
-int atari_keyb_init(void)
+__initfunc(int atari_keyb_init(void))
 {
     /* setup key map */
     key_maps[0]  = ataplain_map;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v2.1.36/linux/arch/m68k/atari/config.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/config.c	Mon May 12 10:35:38 1997
@@ -32,6 +32,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -106,7 +107,7 @@
  * a temporary VBR and a vector table for the duration of the test.
  */
 
-static int hwreg_present( volatile void *regp )
+__initfunc(static int hwreg_present( volatile void *regp ))
 {
     int	ret = 0;
     long	save_sp, save_vbr;
@@ -132,9 +133,8 @@
 }
   
 #if 0
-static int hwreg_present_bywrite( volatile void *regp,
-				 unsigned char val )
-
+__initfunc(static int
+hwreg_present_bywrite(volatile void *regp, unsigned char val))
 {
     int		ret;
     long	save_sp, save_vbr;
@@ -166,7 +166,7 @@
 /* Basically the same, but writes a value into a word register, protected
  * by a bus error handler */
 
-static int hwreg_write( volatile void *regp, unsigned short val )
+__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
 {
 	int		ret;
 	long	save_sp, save_vbr;
@@ -201,7 +201,7 @@
  * should be readable without trouble (from channel A!).
  */
 
-static int scc_test( volatile char *ctla )
+__initfunc(static int scc_test( volatile char *ctla ))
 {
 	if (!hwreg_present( ctla ))
 		return( 0 );
@@ -228,7 +228,7 @@
      *  Parse an Atari-specific record in the bootinfo
      */
 
-int atari_parse_bootinfo(const struct bi_record *record)
+__initfunc(int atari_parse_bootinfo(const struct bi_record *record))
 {
     int unknown = 0;
     const u_long *data = record->data;
@@ -247,7 +247,7 @@
      *  Setup the Atari configuration info
      */
 
-void config_atari(void)
+__initfunc(void config_atari(void))
 {
     memset(&atari_hw_present, 0, sizeof(atari_hw_present));
 
@@ -493,7 +493,8 @@
     }
 }
 
-static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
+__initfunc(static void
+atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
 {
     /* set Timer C data Register */
     mfp.tim_dt_c = INT_TICKS;
@@ -976,7 +977,7 @@
 }
 
 
-static void atari_debug_init(void)
+__initfunc(static void atari_debug_init(void))
 {
 #ifdef CONFIG_KGDB
 	/* if the m68k_debug_device is used by the GDB stub, do nothing here */
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c
--- v2.1.36/linux/arch/m68k/atari/joystick.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/joystick.c	Mon May 12 10:35:38 1997
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/major.h>
 #include <linux/poll.h>
+#include <linux/init.h>
 
 #include <asm/atarikb.h>
 #include <asm/atari_joystick.h>
@@ -128,7 +129,7 @@
 	release_joystick
 };
 
-int atari_joystick_init(void)
+__initfunc(int atari_joystick_init(void))
 {
     joystick[0].active = joystick[1].active = 0;
     joystick[0].ready = joystick[1].ready = 0;
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v2.1.36/linux/arch/m68k/atari/stdma.c	Fri Dec 20 01:19:58 1996
+++ linux/arch/m68k/atari/stdma.c	Mon May 12 10:35:38 1997
@@ -32,6 +32,8 @@
 #include <linux/types.h>
 #include <linux/genhd.h>
 #include <linux/sched.h>
+#include <linux/init.h>
+
 #include <asm/atari_stdma.h>
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
@@ -171,7 +173,7 @@
  *
  */
 
-void stdma_init(void)
+__initfunc(void stdma_init(void))
 {
 	stdma_isr = NULL;
 	request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.1.36/linux/arch/m68k/atari/stram.c	Fri Dec 20 01:19:58 1996
+++ linux/arch/m68k/atari/stram.c	Mon May 12 10:35:38 1997
@@ -149,6 +149,7 @@
 #else
 
 #include <linux/mm.h>
+#include <linux/init.h>
 
 /* ++roman:
  * 
@@ -190,7 +191,7 @@
     /* Overall end of ST-Ram */
 
 
-void atari_stram_init( void )
+__initfunc(void atari_stram_init( void ))
 
 {	int		i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.c linux/arch/m68k/boot/amiga/linuxboot.c
--- v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/amiga/linuxboot.c	Mon May 12 10:35:38 1997
@@ -22,6 +22,8 @@
  *  for more details.
  *
  *  History:
+ *	27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
+ *		    interface version 1.0 (Geert)
  *	03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
  *		    code for ataboot)
  *	30 Dec 1996 Reverted the CPU detection to the old scheme
@@ -791,6 +793,7 @@
 static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
 {
     *cpu = *fpu = 0;
+
     if (SysBase->AttnFlags & AFF_68060)
 	*cpu = CPU_68060;
     else if (SysBase->AttnFlags & AFF_68040)
@@ -799,15 +802,15 @@
 	*cpu = CPU_68030;
     else if (SysBase->AttnFlags & AFF_68020)
 	*cpu = CPU_68020;
+
     if (*cpu == CPU_68040 || *cpu == CPU_68060) {
 	if (SysBase->AttnFlags & AFF_FPU40)
 	    *fpu = *cpu;
-    } else {
-	if (SysBase->AttnFlags & AFF_68882)
-	    *fpu = FPU_68882;
-	else if (SysBase->AttnFlags & AFF_68881)
-	    *fpu = FPU_68881;
-    }
+    } else if (SysBase->AttnFlags & AFF_68882)
+	*fpu = FPU_68882;
+    else if (SysBase->AttnFlags & AFF_68881)
+	*fpu = FPU_68881;
+
     *mmu = *cpu;
 }
 
@@ -1047,7 +1050,7 @@
 	compat_bootinfo.cputype |= COMPAT_FPU_68040;
     else if (bi.fputype & FPU_68060)
 	compat_bootinfo.cputype |= COMPAT_FPU_68060;
-    else {
+    else if (bi.fputype) {
 	Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
 	return(0);
     }
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.h linux/arch/m68k/boot/amiga/linuxboot.h
--- v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.h	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/amiga/linuxboot.h	Mon May 12 10:35:38 1997
@@ -31,7 +31,7 @@
      *  Amiboot Version
      */
 
-#define AMIBOOT_VERSION		"5.4"
+#define AMIBOOT_VERSION		"5.5"
 
 
     /*
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.1.36/linux/arch/m68k/kernel/ints.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/ints.c	Mon May 12 10:35:38 1997
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -79,7 +80,7 @@
  * the IRQ handling routines.
  */
 
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.1.36/linux/arch/m68k/kernel/m68k_ksyms.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Mon May 12 10:35:38 1997
@@ -6,6 +6,8 @@
 #include <linux/mm.h>
 #include <linux/user.h>
 #include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
 
 #include <asm/setup.h>
 #include <asm/machdep.h>
@@ -14,6 +16,7 @@
 #include <asm/semaphore.h>
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
+#include <asm/softirq.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 extern char m68k_debug_device[];
@@ -40,6 +43,7 @@
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(__m68k_bh_counter);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.36/linux/arch/m68k/kernel/process.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/process.c	Mon May 12 10:35:38 1997
@@ -10,6 +10,7 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -30,6 +31,22 @@
 #include <asm/machdep.h>
 #include <asm/setup.h>
 
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+
+struct mm_struct init_mm = INIT_MM;
+struct task_struct init_task = INIT_TASK;
+
 asmlinkage void ret_from_exception(void);
 
 /*
@@ -46,8 +63,16 @@
 	/* endless idle loop with no priority at all */
 	current->priority = -100;
 	current->counter = -100;
-	for (;;)
+	for (;;){
+		if (!need_resched)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+			/* block out HSYNC on the atari (falcon) */
+			__asm__("stop #0x2200" : : : "cc");
+#else /* portable version */
+			__asm__("stop #0x2000" : : : "cc");
+#endif /* machine compilation types */ 
 		schedule();
+	}
 	ret = 0;
 out:
 	unlock_kernel();
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.36/linux/arch/m68k/kernel/ptrace.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/ptrace.c	Mon May 12 10:35:38 1997
@@ -52,18 +52,6 @@
 	PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
 };
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * Get contents of register REGNO in task TASK.
  */
@@ -340,7 +328,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		goto out;
 	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.1.36/linux/arch/m68k/kernel/setup.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/setup.c	Mon May 12 10:35:38 1997
@@ -18,6 +18,7 @@
 #include <linux/genhd.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -55,13 +56,13 @@
 static char m68k_command_line[CL_SIZE];
 char saved_command_line[CL_SIZE];
 
-void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
 /* machine dependent keyboard functions */
-int (*mach_keyb_init) (void);
+int (*mach_keyb_init) (void) __initdata;
 int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
 void (*mach_kbd_leds) (unsigned int) = NULL;
 /* machine dependent irq functions */
-void (*mach_init_IRQ) (void);
+void (*mach_init_IRQ) (void) __initdata;
 void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
 void (*mach_get_model) (char *model) = NULL;
 int (*mach_get_hardware_list) (char *buffer) = NULL;
@@ -73,12 +74,12 @@
 int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
-struct fb_info *(*mach_fb_init)(long *);
+struct fb_info *(*mach_fb_init)(long *) __initdata;
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_video_setup) (char *, int *);
+void (*mach_video_setup) (char *, int *) __initdata;
 #ifdef CONFIG_BLK_DEV_FD
-int (*mach_floppy_init) (void) = NULL;
-void (*mach_floppy_setup) (char *, int *) = NULL;
+int (*mach_floppy_init) (void) __initdata = NULL;
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
 void (*mach_floppy_eject) (void) = NULL;
 #endif
 
@@ -94,7 +95,7 @@
 #define MASK_256K 0xfffc0000
 
 
-static void m68k_parse_bootinfo(const struct bi_record *record)
+__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
 {
     while (record->tag != BI_LAST) {
 	int unknown = 0;
@@ -141,8 +142,8 @@
     }
 }
 
-void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
-		unsigned long * memory_end_p)
+ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+		unsigned long * memory_end_p))
 {
 	unsigned long memory_start, memory_end;
 	extern int _etext, _edata, _end;
@@ -337,7 +338,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_FD
-int floppy_init(void)
+__initfunc(int floppy_init(void))
 {
 	if (mach_floppy_init)
 		return mach_floppy_init();
@@ -345,7 +346,7 @@
 		return 0;
 }
 
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
 {
 	if (mach_floppy_setup)
 		mach_floppy_setup (str, ints);
@@ -358,7 +359,7 @@
 }
 #endif
 
-unsigned long arch_kbd_init(void)
+__initfunc(unsigned long arch_kbd_init(void))
 {
 	return mach_keyb_init();
 }
@@ -372,7 +373,7 @@
 		*year = *mon = *day = *hour = *min = *sec = 0;
 }
 
-void video_setup (char *options, int *ints)
+__initfunc(void video_setup (char *options, int *ints))
 {
 	if (mach_video_setup)
 		mach_video_setup (options, ints);
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.1.36/linux/arch/m68k/kernel/signal.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/signal.c	Mon May 12 10:35:38 1997
@@ -42,7 +42,9 @@
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+			 int options, unsigned long *ru);
+
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
 
 const int frame_extra_sizes[16] = {
@@ -466,7 +468,7 @@
 			if (signr != SIGCHLD)
 				continue;
 			/* check for SIGCHLD: it's special */
-			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+			while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
 				/* nothing */;
 			continue;
 		}
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- v2.1.36/linux/arch/m68k/kernel/time.c	Fri Nov 22 05:56:35 1996
+++ linux/arch/m68k/kernel/time.c	Mon May 12 10:35:38 1997
@@ -27,6 +27,24 @@
   return -1;
 }
 
+static inline void do_profile (unsigned long pc)
+{
+	if (prof_buffer && current->pid) {
+		extern int _stext;
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+		if (pc < prof_len)
+			++prof_buffer[pc];
+		else
+		/*
+		 * Dont ignore out-of-bounds PC values silently,
+		 * put them into the last histogram slot, so if
+		 * present, they will show up as a sharp peak.
+		 */
+			++prof_buffer[prof_len-1];
+	}
+}
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
@@ -37,6 +55,9 @@
 	static long last_rtc_update=0;
 
 	do_timer(regs);
+
+	if (!user_mode(regs))
+		do_profile(regs->pc);
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.1.36/linux/arch/m68k/kernel/traps.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/traps.c	Mon May 12 10:35:38 1997
@@ -27,6 +27,7 @@
 #include <linux/user.h>
 #include <linux/string.h>
 #include <linux/linkage.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
@@ -63,7 +64,7 @@
     __ALIGN_STR "\n"
     SYMBOL_NAME_STR(nmihandler) ": rte");
 
-void trap_init (void)
+__initfunc(void trap_init (void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.36/linux/arch/m68k/mm/init.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/m68k/mm/init.c	Mon May 12 10:35:38 1997
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/init.h>
 #ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
@@ -116,9 +117,8 @@
 	return ptablep;
 }
 
-static unsigned long map_chunk (unsigned long addr,
-				unsigned long size,
-				unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
 {
 #define ONEMEG	(1024*1024)
 #define L3TREESIZE (256*1024)
@@ -283,6 +283,11 @@
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
+/* References to section boundaries */
+
+extern char _text, _etext, _edata, __bss_start, _end;
+extern char __init_begin, __init_end;
+
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 /*
@@ -291,7 +296,7 @@
  * The parameters are pointers to where to stick the starting and ending
  * addresses  of available kernel virtual memory.
  */
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
 {
 	int chunk;
 	unsigned long mem_avail = 0;
@@ -395,12 +400,12 @@
 	return PAGE_ALIGN(free_area_init (start_mem, end_mem));
 }
 
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
 	int codepages = 0;
 	int datapages = 0;
+	int initpages = 0;
 	unsigned long tmp;
-	extern int _etext;
 
 	end_mem &= PAGE_MASK;
 	high_memory = (void *) end_mem;
@@ -448,8 +453,15 @@
 		if (VTOP (tmp) >= mach_max_dma_address)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
-			if (tmp < (unsigned long)&_etext)
-				codepages++;
+			if (tmp >= (unsigned long)&_text
+			    && tmp < (unsigned long)&_edata) {
+				if (tmp < (unsigned long) &_etext)
+					codepages++;
+				else
+					datapages++;
+			} else if (tmp >= (unsigned long) &__init_begin
+				   && tmp < (unsigned long) &__init_end)
+				initpages++;
 			else
 				datapages++;
 			continue;
@@ -461,16 +473,26 @@
 #endif
 			free_page(tmp);
 	}
-	printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
+	printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
 	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
 	       max_mapnr << (PAGE_SHIFT-10),
 	       codepages << (PAGE_SHIFT-10),
-	       datapages << (PAGE_SHIFT-10));
+	       datapages << (PAGE_SHIFT-10),
+	       initpages << (PAGE_SHIFT-10));
 }
 
 void free_initmem(void)
 {
-	/* To be written */
+	unsigned long addr;
+
+	addr = (unsigned long)&__init_begin;
+	for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+		free_page(addr);
+	}
+	printk ("Freeing unused kernel memory: %dk freed\n",
+		(&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.1.36/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.1.36/linux/arch/m68k/vmlinux.lds	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/vmlinux.lds	Mon May 12 10:35:38 1997
@@ -0,0 +1,56 @@
+/* ld script to make m68k Linux kernel */
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x1000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x4e75
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  _edata = .;			/* End of data section */
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.1.36/linux/arch/mips/kernel/process.c	Thu Dec 19 06:48:08 1996
+++ linux/arch/mips/kernel/process.c	Mon May 12 10:35:38 1997
@@ -29,6 +29,22 @@
 #include <asm/stackframe.h>
 #include <asm/io.h>
 
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+
+struct mm_struct init_mm = INIT_MM;
+struct task_struct init_task = INIT_TASK;
+
 asmlinkage void ret_from_sys_call(void);
 
 /*
diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.1.36/linux/arch/mips/kernel/ptrace.c	Wed Dec 13 02:39:44 1995
+++ linux/arch/mips/kernel/ptrace.c	Mon May 12 10:35:38 1997
@@ -33,18 +33,6 @@
  */
 #define MAGICNUMBER 68
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * this routine will get a word off of the processes privileged stack. 
  * the offset is how far from the base addr as stored in the TSS.  
@@ -295,7 +283,7 @@
 	}
 	if (pid == 1)		/* you may not mess with init */
 		return -EPERM;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		return -ESRCH;
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h
--- v2.1.36/linux/arch/mips/kernel/syscalls.h	Wed Dec 13 02:39:44 1995
+++ linux/arch/mips/kernel/syscalls.h	Mon May 12 10:35:38 1997
@@ -174,3 +174,4 @@
 SYS(sys_munlock, 2)				/* 4155 */
 SYS(sys_mlockall, 1)
 SYS(sys_munlockall, 0)
+SYS(sys_nfsservctl, 3)
diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v2.1.36/linux/arch/mips/kernel/traps.c	Wed Dec 13 02:39:44 1995
+++ linux/arch/mips/kernel/traps.c	Mon May 12 10:35:38 1997
@@ -178,6 +178,7 @@
 
 void do_ades(struct pt_regs *regs)
 {
+	struct task_struct *p;
 	unsigned long	pc = regs->cp0_epc;
 	int	i;
 
@@ -187,12 +188,14 @@
 		return;
 	}
 while(1);
-	for(i=0; i<NR_TASKS;i++)
-		if(task[i] && task[i]->pid >= 2)
-		{
-			printk("Process %d\n", task[i]->pid);
-			dump_list_process(task[i], pc);
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(p->pid >= 2) {
+			printk("Process %d\n", p->pid);
+			dump_list_process(p, pc);
 		}
+	}
+	read_unlock(&tasklist_lock);
 	show_regs(regs);
 	dump_tlb_nonwired();
 	send_sig(SIGSEGV, current, 1);
@@ -251,14 +254,16 @@
 
 void do_ri(struct pt_regs *regs)
 {
+	struct task_struct *p;
 	int	i;
 
-	for(i=0; i<NR_TASKS;i++)
-		if(task[i] && task[i]->pid >= 2)
-		{
-			printk("Process %d\n", task[i]->pid);
-			dump_list_process(task[i], 0x7ffff000);
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(p->pid >= 2) {
+			printk("Process %d\n", p->pid);
+			dump_list_process(p, 0x7ffff000);
 		}
+	}
 	show_regs(regs);
 while(1);
 	send_sig(SIGILL, current, 1);
diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.1.36/linux/arch/ppc/kernel/misc.S	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/misc.S	Mon May 12 10:35:38 1997
@@ -855,5 +855,6 @@
 	.long sys_mremap
 	.long SYMBOL_NAME(sys_setresuid)
 	.long SYMBOL_NAME(sys_getresuid)
-	.space (NR_syscalls-165)*4
+	.long SYMBOL_NAME(sys_nfsservctl)
+	.space (NR_syscalls-166)*4
 
diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.36/linux/arch/ppc/kernel/process.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/ppc/kernel/process.c	Mon May 12 10:35:38 1997
@@ -29,6 +29,24 @@
 #include <asm/io.h>
 
 #include <asm/ppc_machine.h>
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
+unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+
+struct mm_struct init_mm = INIT_MM;
+struct task_struct init_task = INIT_TASK;
+
+
 int dump_fpu(void);
 void hard_reset_now(void);
 void switch_to(struct task_struct *, struct task_struct *);
diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.1.36/linux/arch/ppc/kernel/ptrace.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/ppc/kernel/ptrace.c	Mon May 12 10:35:38 1997
@@ -42,18 +42,6 @@
 static int regoff[] = {
 };
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * Get contents of register REGNO in task TASK.
  */
@@ -394,7 +382,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		goto out;
 	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
diff -u --recursive --new-file v2.1.36/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.36/linux/arch/ppc/mm/init.c	Mon Apr 14 16:28:06 1997
+++ linux/arch/ppc/mm/init.c	Mon May 12 10:35:38 1997
@@ -58,69 +58,62 @@
 
 void show_mem(void)
 {
-  unsigned long i,free = 0,total = 0,reserved = 0;
-  unsigned long shared = 0;
-  PTE *ptr;
-  unsigned long full = 0, overflow = 0;
-  unsigned int ti;
+	struct task_struct *p;
+	unsigned long i,free = 0,total = 0,reserved = 0;
+	unsigned long shared = 0;
+	PTE *ptr;
+	unsigned long full = 0, overflow = 0;
+	unsigned int ti;
 
-  printk("Mem-info:\n");
-  show_free_areas();
-  printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-  i = MAP_NR(high_memory);
-  while (i-- > 0) {
-    total++;
-    if (PageReserved(mem_map+i))
-      reserved++;
-    else if (!atomic_read(&mem_map[i].count))
-      free++;
-    else
-      shared += atomic_read(&mem_map[i].count) - 1;
-  }
-  printk("%lu pages of RAM\n",total);
-  printk("%lu free pages\n",free);
-  printk("%lu reserved pages\n",reserved);
-  printk("%lu pages shared\n",shared);
-  show_buffers();
+	printk("Mem-info:\n");
+	show_free_areas();
+	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	i = MAP_NR(high_memory);
+	while (i-- > 0) {
+		total++;
+		if (PageReserved(mem_map+i))
+			reserved++;
+		else if (!atomic_read(&mem_map[i].count))
+			free++;
+		else
+			shared += atomic_read(&mem_map[i].count) - 1;
+	}
+	printk("%lu pages of RAM\n",total);
+	printk("%lu free pages\n",free);
+	printk("%lu reserved pages\n",reserved);
+	printk("%lu pages shared\n",shared);
+	show_buffers();
 #ifdef CONFIG_NET
-  show_net_buffers();
+	show_net_buffers();
 #endif
 #ifdef HASHSTATS
-  printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
-  for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ )
-  {
-    if ( hashhits[i] >= 20 )
-    {
-      printk("[%lu] \t %lu\n", i,hashhits[i]);
-    }
-  }
+	printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
+	for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
+		if ( hashhits[i] >= 20 )
+			printk("[%lu] \t %lu\n", i,hashhits[i]);
+	}
 #endif
   
-  for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++)
-  {
-    if (ptr->v)
-    {
-      full++;
-      if (ptr->h == 1)
-	overflow++;
-    }
-  }
-  printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
-	 Hash_size>>10,	(Hash_size/(sizeof(PTE)*8)) >> 10,
-	 full,Hash_size/sizeof(PTE),
-	 (full*100)/(Hash_size/sizeof(PTE)),
-	 overflow);
-  printk(" Task  context    vsid0\n");
-  for ( ti = 0; ti < NR_TASKS ; ti++ );
-  {
-    if ( task[ti] )
-    {
-      printk("%5d %8x %8x\n",
-	     task[ti]->pid,task[ti]->mm->context,
-	     ((SEGREG *)task[ti]->tss.segs)[0].vsid);
-    }
-  }
-      
+	for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
+		if (ptr->v) {
+			full++;
+			if (ptr->h == 1)
+				overflow++;
+		}
+	}
+	printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
+	       Hash_size>>10,	(Hash_size/(sizeof(PTE)*8)) >> 10,
+	       full,Hash_size/sizeof(PTE),
+	       (full*100)/(Hash_size/sizeof(PTE)),
+	       overflow);
+	printk(" Task  context    vsid0\n");
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		printk("%5d %8x %8x\n",
+		       p->pid,p->mm->context,
+		       ((SEGREG *)p->tss.segs)[0].vsid);
+	}
+	read_unlock(&tasklist_lock);
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.1.36/linux/arch/sparc/Makefile	Mon Apr 14 16:28:06 1997
+++ linux/arch/sparc/Makefile	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $
+# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -21,7 +21,7 @@
 #LINKFLAGS = -N -Ttext 0xf0004000
 LINKFLAGS = -T arch/sparc/vmlinux.lds
 
-HEAD := arch/sparc/kernel/head.o
+HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
 
 SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
 	arch/sparc/prom
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/bnet.c linux/arch/sparc/ap1000/bnet.c
--- v2.1.36/linux/arch/sparc/ap1000/bnet.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/bnet.c	Mon May 12 10:35:38 1997
@@ -872,12 +872,12 @@
   len = req->size - sizeof(*req);
   if (len == 0) {
     int pid = req->data[1];
-    for_each_task(p) 
-      if (p->pid == pid) {
-	send_sig(sig,p,1);
-	return;
-      }
-    printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
+    p = find_task_by_pid(pid);
+
+    if(p)
+	    send_sig(sig, p, 1);
+    else
+	    printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
     return;
   }
 
@@ -889,9 +889,11 @@
   read_bif(name,len);
   name[len] = 0;
 
+  read_lock(&tasklist_lock);
   for_each_task(p) 
     if (strcmp(name,p->comm) == 0)
       send_sig(sig,p,1);
+  read_unlock(&tasklist_lock);
 }
 
 
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/hw.c linux/arch/sparc/ap1000/hw.c
--- v2.1.36/linux/arch/sparc/ap1000/hw.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/hw.c	Mon May 12 10:35:38 1997
@@ -86,14 +86,21 @@
 static void show_ptasks(void)
 {
 	extern struct task_struct *task[];
+	struct task_struct *p;
 	int i;
 	int count=0;
 
-	for (i=MPP_TASK_BASE;i<NR_TASKS;i++)
-		if (task[i]) {
-			show_task(task[i]);
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		struct task_struct **tp = p->tarray_ptr;
+
+		if(tp >= &task[MPP_TASK_BASE]) {
+			show_task(p);
 			count++;
 		}
+	}
+	read_unlock(&tasklist_lock);
+
 	if (count == 0)
 		printk("no parallel tasks on cell %d\n",mpp_cid());
 }
@@ -101,14 +108,18 @@
 static void show_utasks(void)
 {
 	extern struct task_struct *task[];
+	struct task_struct *p;
 	int i;
 	int count=0;
 
-	for (i=0;i<NR_TASKS;i++)
-		if (task[i] && task[i]->uid > 1)  {
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(p->uid > 1) {
 			show_task(task[i]);
 			count++;
 		}
+	}
+	read_unlock(&tasklist_lock);
 
 	if (count == 0)
 		printk("no user tasks on cell %d\n",mpp_cid());
@@ -118,15 +129,19 @@
 static void show_otasks(void)
 {
 	extern struct task_struct *task[];
+	struct task_struct *p;
 	int i;
 	int count=0;
 	extern int ap_current_uid;
 
-	for (i=0;i<NR_TASKS;i++)
-		if (task[i] && task[i]->uid == ap_current_uid)  {
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(p->uid == ap_current_uid) {
 			show_task(task[i]);
 			count++;
 		}
+	}
+	read_unlock(&tasklist_lock);
 
 	if (count == 0)
 		printk("no tasks on cell %d\n",mpp_cid());
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c
--- v2.1.36/linux/arch/sparc/ap1000/mpp.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/mpp.c	Mon May 12 10:35:38 1997
@@ -66,6 +66,7 @@
 
 	if (block_parallel_tasks) return -1000;
 
+	/* XXX task[] fixme */
 	if (last_task && last_task != tsk->taskid && task[last_task] &&
 	    !msc_switch_ok()) return -1000;
 
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.1.36/linux/arch/sparc/kernel/Makefile	Mon Apr 14 16:28:07 1997
+++ linux/arch/sparc/kernel/Makefile	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $
+# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -28,7 +28,7 @@
 CHECKASM_CC	=	$(CC)
 endif
 
-all: kernel.o head.o
+all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S
--- v2.1.36/linux/arch/sparc/kernel/etrap.S	Mon Mar 17 14:54:20 1997
+++ linux/arch/sparc/kernel/etrap.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $
+/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -129,15 +129,23 @@
 trap_setup_from_user:
 	/* We can't use %curptr yet. */
 	LOAD_CURRENT(t_kstack, t_twinmask)
+
+	mov	1, %t_twinmask
+	sll	%t_twinmask, (PAGE_SHIFT + 1), %t_twinmask
+	sub	%t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask
+	add	%t_kstack, %t_twinmask, %t_kstack
+
 	mov	1, %t_twinmask
-	ld	[%t_kstack + AOFF_task_saved_kernel_stack], %t_kstack
 	sll	%t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
 
 	/* Build pt_regs frame. */
 	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
 	/* Clear current->tss.w_saved */
-	LOAD_CURRENT(curptr, g1)
+	mov	1, %curptr
+	sll	%curptr, (PAGE_SHIFT + 1), %curptr
+	sub	%curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr
+	sub	%t_kstack, %curptr, %curptr
 	st	%g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved]
 
 	/* See if we are in the trap window. */
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.1.36/linux/arch/sparc/kernel/head.S	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/kernel/head.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.81 1997/04/16 07:15:48 davem Exp $
+/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -393,12 +393,6 @@
 	BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
 	BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
 
-	.globl	C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack)
-	.globl	C_LABEL(cpu3_stack)
-C_LABEL(cpu0_stack):			.skip 0x2000
-C_LABEL(cpu1_stack):			.skip 0x2000
-C_LABEL(cpu2_stack):			.skip 0x2000
-C_LABEL(cpu3_stack):			.skip 0x2000
 #endif
 	.skip 4096
 
@@ -742,6 +736,9 @@
 		jmpl	%g1, %g0
 		 nop
 
+	/* This is to align init_task_union properly, be careful. -DaveM */
+	.align	8192
+
 /* The code above should be at beginning and we have to take care about
  * short jumps, as branching to .text.init section from .text is usually
  * impossible */
@@ -986,12 +983,10 @@
 		/* Initialize the umask value for init_task just in case.
 		 * But first make current_set[0] point to something useful.
 		 */
-		set	C_LABEL(init_task), %g6
+		set	C_LABEL(init_task_union), %g6
 		set	C_LABEL(current_set), %g2
 		st	%g6, [%g2]
 
-		set	C_LABEL(bootup_kernel_stack), %g3
-		st	%g3, [%g6 + AOFF_task_kernel_stack_page]
 		st	%g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask]
 
 /* Compute NWINDOWS and stash it away. Now uses %wim trick explained
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- v2.1.36/linux/arch/sparc/kernel/init_task.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc/kernel/init_task.c	Mon May 12 10:35:38 1997
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.36/linux/arch/sparc/kernel/process.c	Mon Apr 14 16:28:07 1997
+++ linux/arch/sparc/kernel/process.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $
+/*  $Id: process.c,v 1.96 1997/05/01 08:53:33 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -441,12 +441,12 @@
 
 	if(regs->psr & PSR_PS)
 		stack_offset -= REGWIN_SZ;
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+	childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset));
 	copy_regs(childregs, regs);
 	new_stack = (((struct reg_window *) childregs) - 1);
 	copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
 
-	p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
+	p->tss.ksp = (unsigned long) new_stack;
 #ifdef __SMP__
 	p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8);
 	p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL;
@@ -467,7 +467,7 @@
 		p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 		p->tss.current_ds = USER_DS;
 
-		if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+		if (sp != regs->u_regs[UREG_FP]) {
 			struct sparc_stackf *childstack;
 			struct sparc_stackf *parentstack;
 
@@ -475,9 +475,8 @@
 			 * This is a clone() call with supplied user stack.
 			 * Set some valid stack frames to give to the child.
 			 */
-			childstack = (struct sparc_stackf *)sp;
-			parentstack = (struct sparc_stackf *)
-					current->tss.kregs->u_regs[UREG_FP];
+			childstack = (struct sparc_stackf *) sp;
+			parentstack = (struct sparc_stackf *) regs->u_regs[UREG_FP];
 
 #if 0
 			printk("clone: parent stack:\n");
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.1.36/linux/arch/sparc/kernel/ptrace.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/kernel/ptrace.c	Mon May 12 10:35:38 1997
@@ -24,18 +24,6 @@
 
 #define MAGIC_CONSTANT 0x80000000
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * This routine gets a long from any process space by following the page
  * tables. NOTE! You should check that the long isn't on a page boundary,
@@ -533,7 +521,7 @@
 		goto out;
 	}
 #endif
-	if(!(child = get_task(pid))) {
+	if(!(child = find_task_by_pid(pid))) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.36/linux/arch/sparc/kernel/smp.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/kernel/smp.c	Mon May 12 10:35:38 1997
@@ -4,16 +4,18 @@
  */
 
 #include <asm/head.h>
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/tasks.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
 #include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
@@ -24,6 +26,9 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
 #define IRQ_RESCHEDULE		13
 #define IRQ_STOP_CPU		14
 #define IRQ_CROSS_CALL		15
@@ -118,16 +123,6 @@
 	cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */
 }
 
-/*
- *	Architecture specific routine called by the kernel just before init is
- *	fired off. This allows the BP to have everything in order [we hope].
- *	At the end of this all the AP's will hit the system scheduling and off
- *	we go. Each AP will load the system gdt's and jump through the kernel
- *	init into idle(). At this point the scheduler will one day take over 
- * 	and give them jobs to do. smp_callin is a standard routine
- *	we use to track CPU's as they power up.
- */
-
 void smp_commence(void)
 {
 	/*
@@ -144,7 +139,7 @@
 
 void smp_callin(void)
 {
-	int cpuid = smp_processor_id();
+	int cpuid = hard_smp_processor_id();
 
 	local_flush_cache_all();
 	local_flush_tlb_all();
@@ -183,6 +178,25 @@
 	__sti();
 }
 
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+
+/* Only broken Intel needs this, thus it should not even be referenced
+ * globally...
+ */
+void initialize_secondary(void)
+{
+}
+
+/* Activate a secondary processor. */
+int start_secondary(void *unused)
+{
+	trap_init();
+	init_IRQ();
+	smp_callin();
+	return cpu_idle(NULL);
+}
+
 void cpu_panic(void)
 {
 	printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
@@ -220,6 +234,7 @@
 	cpu_number_map[boot_cpu_id] = 0;
 	cpu_logical_map[0] = boot_cpu_id;
 	klock_info.akp = boot_cpu_id;
+	current->processor = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
 	set_irq_udt(mid_xlate[boot_cpu_id]);
 	smp_setup_percpu_timer();
@@ -233,10 +248,19 @@
 		if(cpu_present_map & (1 << i)) {
 			extern unsigned long sparc_cpu_startup;
 			unsigned long *entry = &sparc_cpu_startup;
+			struct task_struct *p;
 			int timeout;
 
+			/* Cook up an idler for this guy. */
+			kernel_thread(start_secondary, NULL, CLONE_PID);
+
+			p = task[++cpucount];
+
+			p->processor = i;
+			current_set[i] = p;
+
 			/* See trampoline.S for details... */
-			entry += ((i-1) * 6);
+			entry += ((i-1) * 3);
 
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			printk("Starting CPU %d at %p\n", i, entry);
@@ -253,10 +277,10 @@
 			}
 			if(cpu_callin_map[i]) {
 				/* Another "Red Snapper". */
-				cpucount++;
 				cpu_number_map[i] = i;
 				cpu_logical_map[i] = i;
 			} else {
+				cpucount--;
 				printk("Processor %d is stuck.\n", i);
 			}
 		}
@@ -376,14 +400,11 @@
 void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
 		    unsigned long arg3, unsigned long arg4, unsigned long arg5)
 {
-	unsigned long me = smp_processor_id();
-	unsigned long flags, mask;
-	int i, timeout;
-
 	if(smp_processors_ready) {
-		__save_flags(flags);
-		__cli();
-		spin_lock(&cross_call_lock);
+		register int ncpus = smp_num_cpus;
+		unsigned long flags;
+
+		spin_lock_irqsave(&cross_call_lock, flags);
 
 		/* Init function glue. */
 		ccall_info.func = func;
@@ -393,56 +414,47 @@
 		ccall_info.arg4 = arg4;
 		ccall_info.arg5 = arg5;
 
-		/* Init receive/complete mapping. */
-		for(i = 0; i < smp_num_cpus; i++) {
-			ccall_info.processors_in[i] = 0;
-			ccall_info.processors_out[i] = 0;
-		}
-		ccall_info.processors_in[me] = 1;
-		ccall_info.processors_out[me] = 1;
-
-		/* Fire it off. */
-		mask = (cpu_present_map & ~(1 << me));
-		for(i = 0; i < 4; i++) {
-			if(mask & (1 << i))
-				set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
-		}
-
-		/* For debugging purposes right now we can timeout
-		 * on both callin and callexit.
-		 */
-		timeout = CCALL_TIMEOUT;
-		for(i = 0; i < smp_num_cpus; i++) {
-			while(!ccall_info.processors_in[i] && timeout-- > 0)
-				barrier();
-			if(!ccall_info.processors_in[i])
-				goto procs_time_out;
+		/* Init receive/complete mapping, plus fire the IPI's off. */
+		{
+			register void (*send_ipi)(int,int) = set_cpu_int;
+			register unsigned long mask;
+			register int i;
+
+			mask = (cpu_present_map & ~(1 << smp_processor_id()));
+			for(i = 0; i < ncpus; i++) {
+				if(mask & (1 << i)) {
+					ccall_info.processors_in[i] = 0;
+					ccall_info.processors_out[i] = 0;
+					send_ipi(mid_xlate[i], IRQ_CROSS_CALL);
+				} else {
+					ccall_info.processors_in[i] = 1;
+					ccall_info.processors_out[i] = 1;
+				}
+			}
 		}
 
-		/* Run local copy. */
+		/* First, run local copy. */
 		func(arg1, arg2, arg3, arg4, arg5);
 
-		/* Spin on proc dispersion. */
-		timeout = CCALL_TIMEOUT;
-		for(i = 0; i < smp_num_cpus; i++) {
-			while(!ccall_info.processors_out[i] && timeout-- > 0)
-				barrier();
-			if(!ccall_info.processors_out[i])
-				goto procs_time_out;
+		{
+			register int i;
+
+			i = 0;
+			do {
+				while(!ccall_info.processors_in[i])
+					barrier();
+			} while(++i < ncpus);
+
+			i = 0;
+			do {
+				while(!ccall_info.processors_out[i])
+					barrier();
+			} while(++i < ncpus);
 		}
-		spin_unlock(&cross_call_lock);
-		__restore_flags(flags);
-		return; /* made it... */
-
-procs_time_out:
-		printk("smp: Wheee, penguin drops off the bus\n");
-		spin_unlock(&cross_call_lock);
-		__restore_flags(flags);
-		return; /* why me... why me... */
-	}
 
-	/* Just need to run local copy. */
-	func(arg1, arg2, arg3, arg4, arg5);
+		spin_unlock_irqrestore(&cross_call_lock, flags);
+	} else
+		func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
 }
 
 void smp_flush_cache_all(void)
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.36/linux/arch/sparc/kernel/sys_sunos.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.78 1997/04/16 05:56:12 davem Exp $
+/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
 #include <linux/resource.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
+#include <linux/msg.h>
 #include <linux/sem.h>
 #include <linux/signal.h>
 #include <linux/uio.h>
@@ -1031,7 +1032,48 @@
 	unlock_kernel();
 	return ret;
 }
-    
+
+extern asmlinkage int sys_msgget (key_t key, int msgflg);
+extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp,
+				  size_t msgsz, long msgtyp, int msgflg);
+extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp,
+				  size_t msgsz, int msgflg);
+extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2,
+			    unsigned long arg3, unsigned long arg4)
+{
+	struct sparc_stackf *sp;
+	unsigned long arg5;
+	int rval;
+
+	lock_kernel();
+	switch(op) {
+	case 0:
+		rval = sys_msgget((key_t)arg1, (int)arg2);
+		break;
+	case 1:
+		rval = sys_msgctl((int)arg1, (int)arg2,
+				  (struct msqid_ds *)arg3);
+		break;
+	case 2:
+		sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP];
+		arg5 = sp->xxargs[0];
+		rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2,
+				  (size_t)arg3, (long)arg4, (int)arg5);
+		break;
+	case 3:
+		rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2,
+				  (size_t)arg3, (int)arg4);
+		break;
+	default:
+		rval = -EINVAL;
+		break;
+	}
+	unlock_kernel();
+	return rval;
+}
+
 extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
 extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
 extern asmlinkage int sys_shmdt (char *shmaddr);
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.1.36/linux/arch/sparc/kernel/systbls.S	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/kernel/systbls.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.60 1997/04/19 08:52:15 jj Exp $
+/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -106,15 +106,26 @@
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
 	/* "We are the Knights of the Forest of Ni!!" */
-	.long C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall)
-	.long C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam)
-	.long C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min)
-	.long C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep)
+	.long C_LABEL(sys_mlock)
+	.long C_LABEL(sys_munlock)
+	.long C_LABEL(sys_mlockall)
+/*240*/	.long C_LABEL(sys_munlockall)
+	.long C_LABEL(sys_sched_setparam)
+	.long C_LABEL(sys_sched_getparam)
+	.long C_LABEL(sys_sched_setscheduler)
+	.long C_LABEL(sys_sched_getscheduler)
+/*245*/	.long C_LABEL(sys_sched_yield)
+	.long C_LABEL(sys_sched_get_priority_max)
+	.long C_LABEL(sys_sched_get_priority_min)
+	.long C_LABEL(sys_sched_rr_get_interval)
+	.long C_LABEL(sys_nanosleep)
 /*250*/	.long C_LABEL(sys_mremap)
 	.long C_LABEL(sys_sysctl)
-	.long C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nfsservctl)
-	.long C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall)
+	.long C_LABEL(sys_getsid)
+	.long C_LABEL(sys_fdatasync)
+	.long C_LABEL(sys_nfsservctl)
+/*255*/	.long C_LABEL(sys_aplib)
+	.long C_LABEL(sys_nis_syscall)
 
 	/* Now the SunOS syscall table. */
 
@@ -179,7 +190,7 @@
 	.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
 	.long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
-	.long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
+	.long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
 	.long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/tadpole.c linux/arch/sparc/kernel/tadpole.c
--- v2.1.36/linux/arch/sparc/kernel/tadpole.c	Sat Nov  9 00:11:50 1996
+++ linux/arch/sparc/kernel/tadpole.c	Mon May 12 10:35:38 1997
@@ -4,6 +4,8 @@
  */
 
 #include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 
 #include <asm/asi.h>
 #include <asm/oplib.h>
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S
--- v2.1.36/linux/arch/sparc/kernel/trampoline.S	Mon Apr 14 16:28:07 1997
+++ linux/arch/sparc/kernel/trampoline.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $
+/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $
  * trampoline.S: SMP cpu boot-up trampoline code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #include <asm/cprefix.h>
 #include <asm/head.h>
 #include <asm/psr.h>
+#include <asm/page.h>
 #include <asm/asi.h>
 #include <asm/ptrace.h>
 #include <asm/vaddrs.h>
@@ -25,27 +26,18 @@
 C_LABEL(sparc_cpu_startup):
 cpu1_startup:
 	sethi	%hi(C_LABEL(trapbase_cpu1)), %g3
-	or	%g3, %lo(C_LABEL(trapbase_cpu1)), %g3
-	sethi	%hi(C_LABEL(cpu1_stack)), %g2
-	or	%g2, %lo(C_LABEL(cpu1_stack)), %g2
 	b	1f
-	 nop	
+	 or	%g3, %lo(C_LABEL(trapbase_cpu1)), %g3
 
 cpu2_startup:
 	sethi	%hi(C_LABEL(trapbase_cpu2)), %g3
-	or	%g3, %lo(C_LABEL(trapbase_cpu2)), %g3
-	sethi	%hi(C_LABEL(cpu2_stack)), %g2
-	or	%g2, %lo(C_LABEL(cpu2_stack)), %g2
 	b	1f
-	 nop	
+	 or	%g3, %lo(C_LABEL(trapbase_cpu2)), %g3
 
 cpu3_startup:
 	sethi	%hi(C_LABEL(trapbase_cpu3)), %g3
-	or	%g3, %lo(C_LABEL(trapbase_cpu3)), %g3
-	sethi	%hi(C_LABEL(cpu3_stack)), %g2
-	or	%g2, %lo(C_LABEL(cpu3_stack)), %g2
 	b	1f
-	 nop	
+	 or	%g3, %lo(C_LABEL(trapbase_cpu3)), %g3
 
 1:
 	/* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
@@ -62,14 +54,16 @@
 	wr	%g3, 0x0, %tbr
 	WRITE_PAUSE
 
-	/* Give ourselves a stack. */
-	set	0x2000, %g5
-	add	%g2, %g5, %g2		! end of stack
-	sub	%g2, REGWIN_SZ, %sp
-	mov	0, %fp
-
-	/* Set up curptr. */
-	set	C_LABEL(init_task), %g6
+	/* Give ourselves a stack and curptr. */
+	set	C_LABEL(current_set), %g5
+	srl	%g3, 10, %g4
+	and	%g4, 0xc, %g4
+	ld	[%g5 + %g4], %g6
+
+	mov	1, %sp
+	sll	%sp, (PAGE_SHIFT + 1), %sp
+	sub	%sp, REGWIN_SZ, %sp
+	add	%g6, %sp, %sp
 
 	/* Turn on traps (PSR_ET). */
 	rd	%psr, %g1
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S
--- v2.1.36/linux/arch/sparc/kernel/wof.S	Mon Mar 17 14:54:21 1997
+++ linux/arch/sparc/kernel/wof.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $
+/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -234,15 +234,20 @@
 spnwin_patch3:	and	%twin_tmp, 0xff, %twin_tmp	! patched on 7win Sparcs
 		st	%twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask]
 
-	/* Jump onto kernel stack for this process... */
-	ld	[%curptr + AOFF_task_saved_kernel_stack], %sp
+	mov	1, %sp
+	sll	%sp, (PAGE_SHIFT + 1), %sp
+	sub	%sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+	add	%curptr, %sp, %sp
 
 	/* Restore the saved globals and build a pt_regs frame. */
 	mov	%saved_g5, %g5
-	mov	%g6, %l4
 	mov	%saved_g6, %g6
 	STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
-	mov	%l4, %g6
+
+	mov	1, %g6
+	sll	%g6, (PAGE_SHIFT + 1), %g6
+	sub	%g6, (TRACEREG_SZ + REGWIN_SZ), %g6
+	sub	%sp, %g6, %g6
 
 	/* Turn on traps and call c-code to deal with it. */
 	wr	%t_psr, PSR_ET, %psr
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v2.1.36/linux/arch/sparc/kernel/wuf.S	Mon Mar 17 14:54:21 1997
+++ linux/arch/sparc/kernel/wuf.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $
+/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -145,14 +145,17 @@
 	 * to the trap window and call c-code to deal with this.
 	 */
 	LOAD_CURRENT(l4, l5)
-	ld	[%l4 + AOFF_task_saved_kernel_stack], %l5
+
+	mov	1, %l5
+	sll	%l5, (PAGE_SHIFT + 1), %l5
+	sub	%l5, (TRACEREG_SZ + REGWIN_SZ), %l5
+	add	%l4, %l5, %l5
 
 	/* Store globals into pt_regs frame. */
 	STORE_PT_GLOBALS(l5)
 	STORE_PT_YREG(l5, g3)
 
-	/* Save kernel %sp in global while we change windows. */
-	mov	%l5, %g2
+	/* Save current in a global while we change windows. */
 	mov	%l4, %curptr
 
 	save	%g0, %g0, %g0
@@ -166,7 +169,10 @@
 
 	/* LOCATION: Window 'T' */
 
-	mov	%g2, %sp		/* Jump onto kernel %sp being held */
+	mov	1, %sp
+	sll	%sp, (PAGE_SHIFT + 1), %sp
+	sub	%sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+	add	%curptr, %sp, %sp
 
 	/* Build rest of pt_regs. */
 	STORE_PT_INS(sp)
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/lib/irqlock.S linux/arch/sparc/lib/irqlock.S
--- v2.1.36/linux/arch/sparc/lib/irqlock.S	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/lib/irqlock.S	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: irqlock.S,v 1.2 1997/04/19 04:33:37 davem Exp $
+/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $
  * irqlock.S: High performance IRQ global locking and interrupt entry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.36/linux/arch/sparc/mm/srmmu.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/mm/srmmu.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.136 1997/04/20 14:11:51 ecd Exp $
+/* $Id: srmmu.c,v 1.140 1997/05/01 08:53:39 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -659,27 +659,6 @@
 	srmmu_set_entry(ptep, pte_val(pteval));
 }
 
-static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
-{
-	unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
-
-	srmmu_set_entry(ptep, pte_val(pteval));
-	__asm__ __volatile__("
-	lda	[%0] %2, %%g4
-	orcc	%%g4, 0x0, %%g0
-	be	2f
-	 sethi	%%hi(%7), %%g5
-1:	subcc	%%g5, %6, %%g5		! hyper_flush_cache_page
-	bne	1b
-	 sta	%%g0, [%1 + %%g5] %3
-	lda	[%4] %5, %%g0
-2:"	: /* no outputs */
-	: "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
-	  "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
-	  "r" (vac_line_size), "i" (PAGE_SIZE)
-	: "g4", "g5", "cc");
-}
-
 static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
 {
 	register unsigned long a, b, c, d, e, f, g;
@@ -860,30 +839,12 @@
  */
 struct task_struct *srmmu_alloc_task_struct(void)
 {
-	return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
-}
-
-unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
-{
-	unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
-
-	if(!kstk)
-		kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
-
-	return kstk;
+	return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0);
 }
 
 static void srmmu_free_task_struct(struct task_struct *tsk)
 {
-	kfree(tsk);
-}
-
-static void srmmu_free_kernel_stack(unsigned long stack)
-{
-	if(stack < VMALLOC_START)
-		free_pages(stack, 1);
-	else
-		vfree((char *)stack);
+	free_pages((unsigned long)tsk, 1);
 }
 
 /* Tsunami flushes.  It's page level tlb invalidation is not very
@@ -1365,17 +1326,28 @@
 extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
 extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
+static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
+{
+	unsigned long page = ((unsigned long)ptep) & PAGE_MASK;
+
+	srmmu_set_entry(ptep, pte_val(pteval));
+	hypersparc_flush_page_to_ram(page);
+}
+
 static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
 {
+	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
+	hypersparc_flush_page_to_ram((unsigned long)ctxp);
 	hyper_flush_whole_icache();
-	set_pte((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
 }
 
 static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
 	unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
 
-	hypersparc_flush_page_to_ram(page);
+	if(pgdp != swapper_pg_dir)
+		hypersparc_flush_page_to_ram(page);
+
 	if(tsk->mm->context != NO_CONTEXT) {
 		flush_cache_mm(tsk->mm);
 		ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
@@ -1429,26 +1401,29 @@
 
 static void hypersparc_switch_to_context(struct task_struct *tsk)
 {
-	hyper_flush_whole_icache();
 	if(tsk->mm->context == NO_CONTEXT) {
+		ctxd_t *ctxp;
+
 		alloc_context(tsk->mm);
-		flush_cache_mm(tsk->mm);
-		ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
-		flush_tlb_mm(tsk->mm);
+		ctxp = &srmmu_context_table[tsk->mm->context];
+		srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+		hypersparc_flush_page_to_ram((unsigned long)ctxp);
 	}
+	hyper_flush_whole_icache();
 	srmmu_set_context(tsk->mm->context);
 }
 
 static void hypersparc_init_new_context(struct mm_struct *mm)
 {
-	hyper_flush_whole_icache();
+	ctxd_t *ctxp;
 
 	alloc_context(mm);
 
-	flush_cache_mm(mm);
-	ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
-	flush_tlb_mm(mm);
+	ctxp = &srmmu_context_table[mm->context];
+	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+	hypersparc_flush_page_to_ram((unsigned long)ctxp);
 
+	hyper_flush_whole_icache();
 	if(mm == current->mm)
 		srmmu_set_context(mm->context);
 }
@@ -2355,13 +2330,19 @@
 static void hypersparc_destroy_context(struct mm_struct *mm)
 {
 	if(mm->context != NO_CONTEXT && mm->count == 1) {
+		ctxd_t *ctxp;
+
 		/* HyperSparc is copy-back, any data for this
 		 * process in a modified cache line is stale
 		 * and must be written back to main memory now
 		 * else we eat shit later big time.
 		 */
 		flush_cache_mm(mm);
-		ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
+
+		ctxp = &srmmu_context_table[mm->context];
+		srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4))));
+		hypersparc_flush_page_to_ram((unsigned long)ctxp);
+
 		flush_tlb_mm(mm);
 		free_context(mm->context);
 		mm->context = NO_CONTEXT;
@@ -3014,9 +2995,7 @@
         mmu_p2v = srmmu_p2v;
 
 	/* Task struct and kernel stack allocating/freeing. */
-	alloc_kernel_stack = srmmu_alloc_kernel_stack;
 	alloc_task_struct = srmmu_alloc_task_struct;
-	free_kernel_stack = srmmu_free_kernel_stack;
 	free_task_struct = srmmu_free_task_struct;
 
 	quick_kernel_fault = srmmu_quick_kernel_fault;
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.1.36/linux/arch/sparc/mm/sun4c.c	Mon Apr 14 16:28:08 1997
+++ linux/arch/sparc/mm/sun4c.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $
+/* $Id: sun4c.c,v 1.147 1997/05/01 08:53:42 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -1093,8 +1093,7 @@
         panic("sun4c kernel fault handler bolixed...");
 }
 
-/*
- * 4 page buckets for task struct and kernel stack allocation.
+/* 2 page buckets for task struct and kernel stack allocation.
  *
  * TASK_STACK_BEGIN
  * bucket[0]
@@ -1105,24 +1104,17 @@
  *
  * Each slot looks like:
  *
- *  page 1   --  task struct
- *  page 2   --  unmapped, for stack redzone (maybe use for pgd)
- *  page 3/4 --  kernel stack
+ *  page 1 --  task struct + beginning of kernel stack
+ *  page 2 --  rest of kernel stack
  */
 
-struct task_bucket {
-	struct task_struct task;
-	char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
-	char kstack[(PAGE_SIZE*3)];
-};
-
-struct task_bucket *sun4c_bucket[NR_TASKS];
+union task_union *sun4c_bucket[NR_TASKS];
 
 static int sun4c_lowbucket_avail;
 
-#define BUCKET_EMPTY     ((struct task_bucket *) 0)
-#define BUCKET_SIZE      (PAGE_SIZE << 2)
-#define BUCKET_SHIFT     14        /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_EMPTY     ((union task_union *) 0)
+#define BUCKET_SHIFT     (PAGE_SHIFT + 1)        /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_SIZE      (1 << BUCKET_SHIFT)
 #define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
 #define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
 #define BUCKET_PTE(page)       \
@@ -1177,10 +1169,10 @@
 {
 	int start, end;
 
-	/* 16 buckets per segment... */
-	entry &= ~15;
+	/* 32 buckets per segment... */
+	entry &= ~31;
 	start = entry;
-	for(end = (start + 16); start < end; start++)
+	for(end = (start + 32); start < end; start++)
 		if(sun4c_bucket[start] != BUCKET_EMPTY)
 			return;
 
@@ -1190,121 +1182,70 @@
 
 static struct task_struct *sun4c_alloc_task_struct(void)
 {
-	unsigned long addr, page;
+	unsigned long addr, pages;
 	int entry;
 
-	page = get_free_page(GFP_KERNEL);
-	if(!page)
+	pages = __get_free_pages(GFP_KERNEL, 1, 0);
+	if(!pages)
 		return (struct task_struct *) 0;
 
 	for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++)
 		if(sun4c_bucket[entry] == BUCKET_EMPTY)
 			break;
 	if(entry == NR_TASKS) {
-		free_page(page);
+		free_pages(pages, 1);
 		return (struct task_struct *) 0;
 	}
 	if(entry >= sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry + 1;
 
 	addr = BUCKET_ADDR(entry);
-	sun4c_bucket[entry] = (struct task_bucket *) addr;
+	sun4c_bucket[entry] = (union task_union *) addr;
 	if(sun4c_get_segmap(addr) == invalid_segment)
 		get_locked_segment(addr);
-	sun4c_put_pte(addr, BUCKET_PTE(page));
+	sun4c_put_pte(addr, BUCKET_PTE(pages));
+	sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
 
 	return (struct task_struct *) addr;
 }
 
-static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
-{
-	unsigned long saddr = (unsigned long) tsk;
-	unsigned long page[2];
-
-	if(!saddr)
-		return 0;
-	page[0] = __get_free_page(GFP_KERNEL);
-	if(!page[0])
-		return 0;
-	page[1] = __get_free_page(GFP_KERNEL);
-	if(!page[1]) {
-		free_page(page[0]);
-		return 0;
-	}
-
-	saddr += PAGE_SIZE << 1;
-	sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
-	sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
-	return saddr;
-}
-
-static void sun4c_free_kernel_stack_hw(unsigned long stack)
-{
-	unsigned long page[2];
-
-	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
-	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
-	/* We are deleting a mapping, so the flushes here are mandatory. */
-	sun4c_flush_page_hw(stack);
-	sun4c_flush_page_hw(stack + PAGE_SIZE);
-
-	sun4c_put_pte(stack, 0);
-	sun4c_put_pte(stack + PAGE_SIZE, 0);
-	free_page(page[0]);
-	free_page(page[1]);
-}
-
 static void sun4c_free_task_struct_hw(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
-	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
 	int entry = BUCKET_NUM(tsaddr);
 
 	/* We are deleting a mapping, so the flush here is mandatory. */
 	sun4c_flush_page_hw(tsaddr);
+	sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
 
 	sun4c_put_pte(tsaddr, 0);
+	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 	sun4c_bucket[entry] = BUCKET_EMPTY;
 	if(entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
-	free_page(page);
+	free_pages(pages, 1);
 	garbage_collect(entry);
 }
 
-static void sun4c_free_kernel_stack_sw(unsigned long stack)
-{
-	unsigned long page[2];
-
-	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
-	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-
-	/* We are deleting a mapping, so the flushes here are mandatory. */
-	sun4c_flush_page_sw(stack);
-	sun4c_flush_page_sw(stack + PAGE_SIZE);
-
-	sun4c_put_pte(stack, 0);
-	sun4c_put_pte(stack + PAGE_SIZE, 0);
-	free_page(page[0]);
-	free_page(page[1]);
-}
-
 static void sun4c_free_task_struct_sw(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
-	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
 	int entry = BUCKET_NUM(tsaddr);
 
 	/* We are deleting a mapping, so the flush here is mandatory. */
 	sun4c_flush_page_sw(tsaddr);
+	sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
 
 	sun4c_put_pte(tsaddr, 0);
+	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 	sun4c_bucket[entry] = BUCKET_EMPTY;
 	if(entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
-	free_page(page);
+	free_pages(pages, 1);
 	garbage_collect(entry);
 }
 
@@ -1312,8 +1253,8 @@
 {
 	int entry;
 
-	if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
-		prom_printf("task bucket not 4 pages!\n");
+	if(sizeof(union task_union) != (PAGE_SIZE << 1)) {
+		prom_printf("task union not 2 pages!\n");
 		prom_halt();
 	}
 	for(entry = 0; entry < NR_TASKS; entry++)
@@ -2645,7 +2586,6 @@
 		flush_tlb_mm = sun4c_flush_tlb_mm_hw;
 		flush_tlb_range = sun4c_flush_tlb_range_hw;
 		flush_tlb_page = sun4c_flush_tlb_page_hw;
-		free_kernel_stack = sun4c_free_kernel_stack_hw;
 		free_task_struct = sun4c_free_task_struct_hw;
 		switch_to_context = sun4c_switch_to_context_hw;
 		destroy_context = sun4c_destroy_context_hw;
@@ -2658,7 +2598,6 @@
 		flush_tlb_mm = sun4c_flush_tlb_mm_sw;
 		flush_tlb_range = sun4c_flush_tlb_range_sw;
 		flush_tlb_page = sun4c_flush_tlb_page_sw;
-		free_kernel_stack = sun4c_free_kernel_stack_sw;
 		free_task_struct = sun4c_free_task_struct_sw;
 		switch_to_context = sun4c_switch_to_context_sw;
 		destroy_context = sun4c_destroy_context_sw;
@@ -2736,7 +2675,6 @@
         mmu_p2v = sun4c_p2v;
 	
 	/* Task struct and kernel stack allocating/freeing. */
-	alloc_kernel_stack = sun4c_alloc_kernel_stack;
 	alloc_task_struct = sun4c_alloc_task_struct;
 
 	quick_kernel_fault = sun4c_quick_kernel_fault;
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c
--- v2.1.36/linux/arch/sparc/prom/console.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/prom/console.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $
+/* $Id: console.c,v 1.12 1997/05/01 01:41:30 davem Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -42,7 +42,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -83,7 +83,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return i; /* Ugh, we could spin forever on unsupported proms ;( */
@@ -130,7 +130,7 @@
 		save_flags(flags); cli();
 		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
 		__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-				     "r" (&current_set[smp_processor_id()]) :
+				     "r" (&current_set[hard_smp_processor_id()]) :
 				     "memory");
 		restore_flags(flags);
 		if(prom_node_has_property(st_p, "keyboard"))
@@ -177,7 +177,7 @@
 		save_flags(flags); cli();
 		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
 		__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-				     "r" (&current_set[smp_processor_id()]) :
+				     "r" (&current_set[hard_smp_processor_id()]) :
 				     "memory");
 		restore_flags(flags);
 		propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/devmap.c linux/arch/sparc/prom/devmap.c
--- v2.1.36/linux/arch/sparc/prom/devmap.c	Sat Nov  9 00:12:24 1996
+++ linux/arch/sparc/prom/devmap.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: devmap.c,v 1.3 1996/09/19 20:27:19 davem Exp $
+/* $Id: devmap.c,v 1.4 1997/05/01 01:41:31 davem Exp $
  * promdevmap.c:  Map device/IO areas to virtual addresses.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -33,7 +33,7 @@
 	ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
 						    num_bytes);
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return ret;
@@ -49,7 +49,7 @@
 	save_flags(flags); cli();
 	(*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return;
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c
--- v2.1.36/linux/arch/sparc/prom/devops.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/prom/devops.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $
+/* $Id: devops.c,v 1.8 1997/05/01 01:41:31 davem Exp $
  * devops.c:  Device operations using the PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -35,7 +35,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
@@ -60,7 +60,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return 0;
@@ -86,7 +86,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c
--- v2.1.36/linux/arch/sparc/prom/misc.c	Mon Apr 14 16:28:08 1997
+++ linux/arch/sparc/prom/misc.c	Mon May 12 10:35:38 1997
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $
+/* $Id: misc.c,v 1.14 1997/05/01 01:41:32 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -22,7 +22,7 @@
 	(*(romvec->pv_reboot))(bcommand);
 	/* Never get here. */
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 }
@@ -40,7 +40,7 @@
 	else
 		(*(romvec->pv_fortheval.v2_eval))(fstring);
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 }
@@ -72,7 +72,7 @@
 	save_flags(flags); cli();
 	(*(romvec->pv_abort))();
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	install_linux_ticker();
@@ -97,7 +97,7 @@
 	(*(romvec->pv_halt))();
 	/* Never get here. */
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	goto again; /* PROM is out to get me -DaveM */
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c
--- v2.1.36/linux/arch/sparc/prom/mp.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/prom/mp.c	Mon May 12 10:35:39 1997
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $
+/* $Id: mp.c,v 1.8 1997/05/01 01:41:32 davem Exp $
  * mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
  *        these on a UP or else you will halt and catch fire. ;)
  *
@@ -36,7 +36,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
@@ -65,7 +65,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
@@ -94,7 +94,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
@@ -123,7 +123,7 @@
 		break;
 	};
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/segment.c linux/arch/sparc/prom/segment.c
--- v2.1.36/linux/arch/sparc/prom/segment.c	Sat Nov  9 00:12:30 1996
+++ linux/arch/sparc/prom/segment.c	Mon May 12 10:35:39 1997
@@ -1,4 +1,4 @@
-/* $Id: segment.c,v 1.3 1996/09/19 20:27:28 davem Exp $
+/* $Id: segment.c,v 1.4 1997/05/01 01:41:33 davem Exp $
  * segment.c:  Prom routine to map segments in other contexts before
  *             a standalone is completely mapped.  This is for sun4 and
  *             sun4c architectures only.
@@ -22,7 +22,7 @@
 	save_flags(flags); cli();
 	(*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
 	__asm__ __volatile__("ld [%0], %%g6\n\t" : :
-			     "r" (&current_set[smp_processor_id()]) :
+			     "r" (&current_set[hard_smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
 	return;
diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c
--- v2.1.36/linux/arch/sparc/prom/tree.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/prom/tree.c	Mon May 12 10:35:39 1997
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $
+/* $Id: tree.c,v 1.17 1997/05/01 01:41:33 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -18,7 +18,7 @@
 
 /* Macro to restore "current" to the g6 register. */
 #define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \
-			  "r" (&current_set[smp_processor_id()]) : \
+			  "r" (&current_set[hard_smp_processor_id()]) : \
 			  "memory")
 
 static char promlib_buf[128];
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.36/linux/arch/sparc64/kernel/entry.S	Mon Apr 14 16:28:09 1997
+++ linux/arch/sparc64/kernel/entry.S	Mon May 12 10:35:39 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
+/* $Id: entry.S,v 1.15 1997/04/28 14:57:08 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -34,21 +34,37 @@
 	call	sparc64_dtlb_fault_handler
 	 nop
 
+	/* Note, DMMU SFAR not updated for fast tlb data access miss
+	 * traps, so we must use tag access to find the right page.
+	 */
 sparc64_dtlb_refbit_catch:
+	wr	%g0, ASI_DMMU, %asi
 	rdpr	%pstate, %g1
 	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g5
+	srlx	%g5, PAGE_SHIFT, %g5
+	ldxa	[%g0 + TLB_SFSR] %asi, %g4
+	sllx	%g5, PAGE_SHIFT, %g5
 	ba,pt	%xcc, etrap
 	 rd	%pc, %g7
-	call	sparc64_dtlb_refbit_handler
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+
+	clr	%o1					! text_fault == 0
+	mov	%l5, %o3				! address == sfar
+	and	%l4, 0x4, %o2				! write == sfsr.W
+	call	do_sparc64_fault
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
 
 sparc64_itlb_refbit_catch:
 	rdpr	%pstate, %g1
 	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
 	ba,pt	%xcc, etrap
 	 rd	%pc, %g7
-	call	sparc64_dtlb_refbit_handler
-	 nop
+
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+	mov	1, %o1					! text_fault == 1
+	clr	%o2					! write == 0
+	call	do_sparc64_fault
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
 
 	/* Note check out head.h, this code isn't even used for UP,
 	 * for SMP things will be different.  In particular the data
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.1.36/linux/arch/sparc64/kernel/etrap.S	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc64/kernel/etrap.S	Mon May 12 10:35:39 1997
@@ -1,7 +1,7 @@
-/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $
+/* $Id: etrap.S,v 1.12 1997/04/28 14:57:07 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
@@ -11,24 +11,28 @@
 #include <asm/spitfire.h>
 #include <asm/head.h>
 
-/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */
+	/* We assume that pstate, when entering this, has AG and
+	 * IE bits set, MG and IG clear.
+	 *
+	 * We also guarentee for caller that AG %g4 and %g5 will have
+	 * their values preserved and left in %l4 and %l5 respectively
+	 * for him (fault handling needs this).
+	 */
 
 	.text
 	.align	32
 	.globl	etrap, etrap_irq
 etrap:
-	rdpr		%pil, %g4
+	rdpr		%pil, %g2
 etrap_irq:
 	rdpr		%tstate, %g1
-	sllx		%g4, 20, %g4
-	rdpr		%tpc, %g2
-	or		%g1, %g4, %g1
-	rdpr		%tnpc, %g3
+	sllx		%g2, 20, %g2
+	or		%g1, %g2, %g1
 
 	/* What happens more often? etrap when already in priv or from userland? */
 	andcc		%g1, TSTATE_PRIV, %g0
 	bne,a,pn	%xcc, 1f
-	 sub		%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+	 sub		%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
 
 	/* Just when going from userland to privileged mode,
 	 * we have to change this stuff.
@@ -38,41 +42,47 @@
 	 * trap level until PRIMARY_CONTEXT is set to zero, else
 	 * we fall out of NUCLEUS too soon and crash hard.
 	 */
-	rdpr		%wstate, %g5
-	mov		PRIMARY_CONTEXT, %g7
-	ldxa		[%g7] ASI_DMMU, %g4
-	mov		SECONDARY_CONTEXT, %g6
-	stxa		%g0, [%g7] ASI_DMMU
-	stxa		%g4, [%g6] ASI_DMMU
-	wrpr		%g0, 0x0, %tl
-
-	sll		%g5, 3, %g5
-	sethi		%uhi(KERNBASE), %g4
-	or		%g4, %ulo(KERNBASE), %g4
-	sethi		%hi(current_set), %g6
-	or		%g6, %lo(current_set), %g6
-	sllx		%g4, 32, %g4
-	wrpr		%g5, %wstate
-	rdpr		%canrestore, %g5
-	ldx		[%g6 + %g4], %g6
+	mov		PRIMARY_CONTEXT, %g1
+	ldxa		[%g1] ASI_DMMU, %g2
+	stxa		%g0, [%g1] ASI_DMMU
+
+	mov		SECONDARY_CONTEXT, %g1
+	stxa		%g2, [%g1] ASI_DMMU
+
+	rdpr		%wstate, %g1
+	sll		%g1, 3, %g1
+	wrpr		%g1, %wstate
+
+	sethi		%uhi(KERNBASE), %g2
+	or		%g2, %ulo(KERNBASE), %g2
+	sethi		%hi(current_set), %g1
+	or		%g1, %lo(current_set), %g1
+	sllx		%g2, 32, %g2
+	ldx		[%g1 + %g2], %g1
 #ifdef __SMP__
 /* FIXME: Fix the above insn for SMP */
 #endif
+	rdpr		%canrestore, %g2
 	wrpr		%g0, 0, %canrestore
-	wrpr		%g5, 0, %otherwin
-	ba,pt		%xcc, 2f
-	 ldx		[%g6 + AOFF_task_saved_kernel_stack], %g5
+	wrpr		%g2, 0, %otherwin
+
+	ldx		[%g1 + AOFF_task_saved_kernel_stack], %g2
 1:
+	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
+	rdpr		%tpc, %g1
+	rdpr		%tnpc, %g3
+	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_TPC]
+	rd		%y, %g1
+	stx		%g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
+	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_Y]
+
 	wrpr		%g0, 0x0, %tl
-2:
-	rd		%y, %g4
-	stx		%g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE]
-	stx		%g2, [%g5 + REGWIN_SZ + PT_V9_TPC]
-	stx		%g3, [%g5 + REGWIN_SZ + PT_V9_TNPC]
-	stx		%g4, [%g5 + REGWIN_SZ + PT_V9_Y]
+
 	rdpr		%pstate, %g1
-	save		%g5, -STACK_BIAS, %sp
+	save		%g2, -STACK_BIAS, %sp
 	mov		%g1, %l1
+	mov		%g4, %l4
+	mov		%g5, %l5
 	mov		%g7, %l2
 	wrpr		%l1, PSTATE_AG, %pstate
 	stx		%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
@@ -104,11 +114,6 @@
 
 	.globl	etraptl1
 etraptl1:
-	rdpr	%tl, %g4
 	rdpr	%tstate, %g1
-	sub	%g4, 1, %g4
-	rdpr	%tpc, %g2
-	rdpr	%tnpc, %g3
-	wrpr	%g4, 0x0, %tl
 	ba,pt	%xcc, 1b
-	 sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+	 sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.1.36/linux/arch/sparc64/lib/checksum.S	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc64/lib/checksum.S	Mon May 12 10:35:39 1997
@@ -555,7 +555,7 @@
 	add	%i1, %i2, %i1
 2:
 	mov	%i1, %o0
-        wr	%%g0, ASI_S, %%asi
+        wr	%g0, ASI_S, %asi
         call	__bzero_noasi
 	 mov	%i3, %o1
 1:
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S
--- v2.1.36/linux/arch/sparc64/lib/copy_from_user.S	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/lib/copy_from_user.S	Mon May 12 10:35:39 1997
@@ -15,12 +15,16 @@
 
 #include <asm/ptrace.h>
 #include <asm/asi.h>
+#include <asm/head.h>
+
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
 
 #define EX(x,y,a,b,z) 				\
 98: 	x,y;					\
 	.section .fixup,z##alloc,z##execinstr;	\
 	.align	4;				\
-99:	retl;					\
+99:	PRE_RETL				\
+	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
 	.align	4;				\
@@ -33,6 +37,7 @@
 	.section .fixup,z##alloc,z##execinstr;	\
 	.align	4;				\
 99:	c, d, e;				\
+	PRE_RETL				\
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
@@ -234,6 +239,7 @@
 	EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
 	stb	%g2, [%o0]
 1:
+	PRE_RETL
 	retl
  	 clr	%o0
 
@@ -332,6 +338,7 @@
 	EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
 	stb	%g2, [%o0]
 1:
+	PRE_RETL
 	retl
  	 clr	%o0
 
@@ -355,6 +362,7 @@
 	.section .fixup,#alloc,#execinstr
 	.align	4
 97:
+	PRE_RETL
 	retl
 	 mov	%o2, %o0
 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@
 1:
 	and	%g1, 0x7f, %o0
 	add	%o0, %g7, %o0
+	PRE_RETL
 	retl
 	 sub	%o0, %g2, %o0
 51:
@@ -413,6 +422,7 @@
 3:
 	sll	%g2, 2, %g2
 2:
+	PRE_RETL
 	retl
 	 add	%g1, %g2, %o0
 52:
@@ -431,6 +441,7 @@
 	add	%g2, %g4, %g2
 	and	%o2, 0xf, %o0
 	add	%o0, %o3, %o0
+	PRE_RETL
 	retl
 	 sub	%o0, %g2, %o0
 54:
@@ -441,6 +452,7 @@
 	and	%o2, 0xf, %o2
 	sub	%o3, %o1, %o3
 	sub	%o2, %o4, %o2
+	PRE_RETL
 	retl
 	 add	%o2, %o3, %o0
 55:
@@ -452,5 +464,6 @@
 	and	%g2, 1, %g2
 	sll	%o1, 1, %o1
 	add	%o2, %g2, %o0
+	PRE_RETL
 	retl
 	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S
--- v2.1.36/linux/arch/sparc64/lib/copy_to_user.S	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/lib/copy_to_user.S	Mon May 12 10:35:39 1997
@@ -14,13 +14,17 @@
  */
 
 #include <asm/ptrace.h>
+#include <asm/head.h>
 #include <asm/asi.h>
 
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
+
 #define EX(x,y,a,b,z) 				\
 98: 	x,y;					\
 	.section .fixup,z##alloc,z##execinstr;	\
 	.align	4;				\
-99:	retl;					\
+99:	PRE_RETL				\
+	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
 	.align	4;				\
@@ -33,6 +37,7 @@
 	.section .fixup,z##alloc,z##execinstr;	\
 	.align	4;				\
 99:	c, d, e;				\
+	PRE_RETL				\
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
@@ -234,6 +239,7 @@
 	ldub	[%o1], %g2
 	EX(stba	%g2, [%o0] %asi, add %g0, 1,#)
 1:
+	PRE_RETL
 	retl
  	 clr	%o0
 
@@ -332,6 +338,7 @@
 	ldub	[%o1], %g2
 	EX(stba	%g2, [%o0] %asi, add %g0, 1,#)
 1:
+	PRE_RETL
 	retl
  	 clr	%o0
 
@@ -355,6 +362,7 @@
 	.section .fixup,#alloc,#execinstr
 	.align	4
 97:
+	PRE_RETL
 	retl
 	 mov	%o2, %o0
 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@
 1:
 	and	%g1, 0x7f, %o0
 	add	%o0, %g7, %o0
+	PRE_RETL
 	retl
 	 sub	%o0, %g2, %o0
 51:
@@ -413,6 +422,7 @@
 3:
 	sll	%g2, 2, %g2
 2:
+	PRE_RETL
 	retl
 	 add	%g1, %g2, %o0
 52:
@@ -431,6 +441,7 @@
 	add	%g2, %g4, %g2
 	and	%o2, 0xf, %o0
 	add	%o0, %o3, %o0
+	PRE_RETL
 	retl
 	 sub	%o0, %g2, %o0
 54:
@@ -441,6 +452,7 @@
 	and	%o2, 0xf, %o2
 	sub	%o3, %o1, %o3
 	sub	%o2, %o4, %o2
+	PRE_RETL
 	retl
 	 add	%o2, %o3, %o0
 55:
@@ -452,5 +464,6 @@
 	and	%g2, 1, %g2
 	sll	%o1, 1, %o1
 	add	%o2, %g2, %o0
+	PRE_RETL
 	retl
 	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.36/linux/arch/sparc64/mm/init.c	Wed Apr 23 19:01:17 1997
+++ linux/arch/sparc64/mm/init.c	Mon May 12 10:35:39 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $
+/*  $Id: init.c,v 1.25 1997/04/28 14:57:11 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -694,6 +694,11 @@
 		min_free_pages = 16;
 	free_pages_low = min_free_pages + (min_free_pages >> 1);
 	free_pages_high = min_free_pages + min_free_pages;
+
+#if 0
+	printk("Testing fault handling...\n");
+	*(char *)0x00000deadbef0000UL = 0;
+#endif
 }
 
 void free_initmem (void)
diff -u --recursive --new-file v2.1.36/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.1.36/linux/drivers/block/amiflop.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/amiflop.c	Mon May 12 10:35:39 1997
@@ -62,6 +62,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -1712,7 +1713,7 @@
 
 }
 
-static void probe_drives(void)
+__initfunc(static void probe_drives(void))
 {
 	int drive,found;
 
@@ -1860,7 +1861,7 @@
 
 }
 
-int amiga_floppy_init(void)
+__initfunc(int amiga_floppy_init(void))
 {
   int i;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.1.36/linux/drivers/block/ataflop.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/ataflop.c	Mon May 12 10:35:39 1997
@@ -75,6 +75,7 @@
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/system.h>
@@ -1777,7 +1778,7 @@
 
 /* Initialize the 'unit' variable for drive 'drive' */
 
-static void fd_probe( int drive )
+__initfunc(static void fd_probe( int drive ))
 {
 	UD.connected = 0;
 	UDT  = NULL;
@@ -1820,7 +1821,7 @@
  * declared absent.
  */
 
-static int fd_test_drive_present( int drive )
+__initfunc(static int fd_test_drive_present( int drive ))
 {
 	unsigned long timeout;
 	unsigned char status;
@@ -1867,7 +1868,7 @@
  * floppies, additionally start the disk-change and motor-off timers.
  */
 
-static void config_types( void )
+__initfunc(static void config_types( void ))
 {
 	int drive, cnt = 0;
 
@@ -2010,7 +2011,7 @@
 	floppy_revalidate,	/* revalidate */
 };
 
-int atari_floppy_init (void)
+__initfunc(int atari_floppy_init (void))
 {
 	int i;
 
@@ -2070,7 +2071,7 @@
 }
 
 
-void atari_floppy_setup( char *str, int *ints )
+__initfunc(void atari_floppy_setup( char *str, int *ints ))
 {
 	int i;
 	
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ez.c linux/drivers/block/ez.c
--- v2.1.36/linux/drivers/block/ez.c	Wed Dec 18 05:57:28 1996
+++ linux/drivers/block/ez.c	Mon May 12 10:35:39 1997
@@ -101,6 +101,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -256,7 +257,7 @@
 	ez_revalidate		/* revalidate new media */
 };
 
-int ez_init (void)	/* preliminary initialisation */
+__initfunc(int ez_init (void))	/* preliminary initialisation */
 
 {	
 	if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) {
@@ -271,7 +272,7 @@
 	return 0;
 }
 
-static void ez_geninit (struct gendisk *ignored)    /* real init */
+__initfunc(static void ez_geninit (struct gendisk *ignored))    /* real init */
 
 {	int i;
 
@@ -507,7 +508,7 @@
    syntax:	ez=base[,irq[,rep[,nybble]]]
 */
 
-void    ez_setup(char *str, int *ints)
+__initfunc(void ez_setup(char *str, int *ints))
 
 {       if (ints[0] > 0) ez_base = ints[1];
         if (ints[0] > 1) ez_irq = ints[2];
@@ -748,7 +749,7 @@
 
 /* ez_media_check: check for and acknowledge the MC flag */
 
-static void ez_media_check( void )
+__initfunc(static void ez_media_check( void ))
 
 {	int r;
 
@@ -768,7 +769,7 @@
 	disconnect();
 }
 
-static int ez_identify( void )
+__initfunc(static int ez_identify( void ))
 
 
 {	int	k, r;
@@ -800,7 +801,7 @@
 
 #define  word_val(n) 	(ez_scratch[2*n]+256*ez_scratch[2*n+1])
 
-static void ez_get_capacity( void )
+__initfunc(static void ez_get_capacity( void ))
 
 {	int	ez_cylinders;
 
@@ -821,7 +822,7 @@
 		ez_heads,ez_sectors);
 }
 
-static void ez_standby_off( void )
+__initfunc(static void ez_standby_off( void ))
 
 {	connect();
 	wait_for(0,NULL);
@@ -830,7 +831,7 @@
 	disconnect();
 }
 
-static int ez_port_check( void ) 	/* check for 8-bit port */
+__initfunc(static int ez_port_check( void )) 	/* check for 8-bit port */
 
 {	int	r;
 
@@ -843,7 +844,7 @@
 	return 0;
 }
 
-static int ez_detect( void )
+__initfunc(static int ez_detect( void ))
 
 {	int j, k;
 	char sig[EZ_SIGLEN] = EZ_SIG;
diff -u --recursive --new-file v2.1.36/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.36/linux/drivers/block/floppy.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/floppy.c	Mon May 12 10:35:39 1997
@@ -140,6 +140,7 @@
 #include <linux/mc146818rtc.h> /* CMOS defines */
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -3726,7 +3727,7 @@
 
 /* Determine the floppy disk controller type */
 /* This routine was written by David C. Niemi */
-static char get_fdc_version(void)
+__initfunc(static char get_fdc_version(void))
 {
 	int r;
 
@@ -3804,7 +3805,7 @@
 
 /* lilo configuration */
 
-static void floppy_set_flags(int *ints,int param, int param2)
+__initfunc(static void floppy_set_flags(int *ints,int param, int param2))
 {
 	int i;
 
@@ -3817,7 +3818,7 @@
 	DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
 }
 
-static void daring(int *ints,int param, int param2)
+__initfunc(static void daring(int *ints,int param, int param2))
 {
 	int i;
 
@@ -3833,7 +3834,7 @@
 	DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-static void set_cmos(int *ints, int dummy, int dummy2)
+__initfunc(static void set_cmos(int *ints, int dummy, int dummy2))
 {
 	int current_drive=0;
 
@@ -3894,7 +3895,7 @@
 	{ "L40SX", 0, &print_unex, 0, 0 } };
 
 #define FLOPPY_SETUP
-void floppy_setup(char *str, int *ints)
+__initfunc(void floppy_setup(char *str, int *ints))
 {
 	int i;
 	int param;
@@ -3930,7 +3931,7 @@
 
 static int have_no_fdc= -EIO;
 
-int floppy_init(void)
+__initfunc(int floppy_init(void))
 {
 	int i,unit,drive;
 
@@ -4135,7 +4136,7 @@
 
 char *floppy=NULL;
 
-static void parse_floppy_cfg_string(char *cfg)
+__initfunc(static void parse_floppy_cfg_string(char *cfg))
 {
 	char *ptr;
 	int ints[11];
@@ -4151,7 +4152,7 @@
 	}
 }
 
-static void mod_setup(char *pattern, void (*setup)(char *, int *))
+__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *)))
 {
 	unsigned long i;
 	char c;
diff -u --recursive --new-file v2.1.36/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.36/linux/drivers/block/genhd.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/genhd.c	Mon May 12 10:35:39 1997
@@ -191,7 +191,7 @@
 	   */
 		bh->b_state = 0;
 
-		if (le16_to_cpu(*(unsigned short *) (bh->b_data+510)) != MSDOS_LABEL_MAGIC)
+		if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
 			goto done;
 
 		p = (struct partition *) (0x1BE + bh->b_data);
@@ -316,7 +316,7 @@
 #ifdef CONFIG_BLK_DEV_IDE
 check_table:
 #endif
-	if (le16_to_cpu(*(unsigned short *) (0x1fe + data)) != MSDOS_LABEL_MAGIC) {
+	if (*(unsigned short *)  (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
 		brelse(bh);
 		return 0;
 	}
@@ -359,7 +359,7 @@
 				goto read_mbr;	/* start over with new MBR */
 			}
 		} else if (sig <= 0x1ae &&
-			   le16_to_cpu(*(unsigned short *)(data + sig)) == 0x55AA &&
+			   *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) &&
 			   (1 & *(unsigned char *)(data + sig + 2))) {
 			/* DM6 signature in MBR, courtesy of OnTrack */
 			(void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
@@ -424,7 +424,7 @@
 	/*
 	 *  Check for old-style Disk Manager partition table
 	 */
-	if (le16_to_cpu(*(unsigned short *) (data+0xfc)) == MSDOS_LABEL_MAGIC) {
+	if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
 		p = (struct partition *) (0x1be + data);
 		for (i = 4 ; i < 16 ; i++, current_minor++) {
 			p--;
@@ -603,7 +603,7 @@
 }
 
 static int
-amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
+amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
 	struct buffer_head	*bh;
 	struct RigidDiskBlock	*rdb;
@@ -618,13 +618,15 @@
 
 	for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
 		if(!(bh = bread(dev,blk,512))) {
-			printk("Dev %d: unable to read RDB block %d\n",dev,blk);
+			printk("Dev %s: unable to read RDB block %d\n",
+			       kdevname(dev),blk);
 			goto rdb_done;
 		}
-		if (*(__u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
+		if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
 			rdb = (struct RigidDiskBlock *)bh->b_data;
-			if (checksum_block((__u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
-				printk("Dev %d: RDB in block %d has bad checksum\n",dev,blk);
+			if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
+				printk("Dev %s: RDB in block %d has bad checksum\n",
+				       kdevname(dev),blk);
 				brelse(bh);
 				continue;
 			}
@@ -633,14 +635,14 @@
 			brelse(bh);
 			for (part = 1; blk > 0 && part <= 16; part++) {
 				if (!(bh = bread(dev,blk,512))) {
-					printk("Dev %d: unable to read partition block %d\n",
-						       dev,blk);
+					printk("Dev %s: unable to read partition block %d\n",
+						       kdevname(dev),blk);
 					goto rdb_done;
 				}
 				pb  = (struct PartitionBlock *)bh->b_data;
 				blk = htonl(pb->pb_Next);
 				if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
-				    (__u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
+				    (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
 					
 					/* Tell Kernel about it */
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.1.36/linux/drivers/block/hd.c	Fri Apr  4 08:52:17 1997
+++ linux/drivers/block/hd.c	Mon May 12 10:35:39 1997
@@ -39,6 +39,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
 
 #define REALLY_SLOW_IO
 #include <asm/system.h>
@@ -110,7 +111,7 @@
 }
 #endif
 
-void hd_setup(char *str, int *ints)
+__initfunc(void hd_setup(char *str, int *ints))
 {
 	int hdind = 0;
 
@@ -792,7 +793,7 @@
 	block_fsync		/* fsync */
 };
 
-int hd_init(void)
+__initfunc(int hd_init(void))
 {
 	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
 		printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.1.36/linux/drivers/block/ide-disk.c	Wed Dec 11 06:45:54 1996
+++ linux/drivers/block/ide-disk.c	Mon May 12 10:35:39 1997
@@ -48,7 +48,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
@@ -59,6 +58,7 @@
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/delay.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.1.36/linux/drivers/block/ide-floppy.c	Thu Mar 27 14:40:02 1997
+++ linux/drivers/block/ide-floppy.c	Mon May 12 17:39:50 1997
@@ -726,7 +726,7 @@
 		return;
 	}
 #ifdef CONFIG_BLK_DEV_TRITON
-	if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
 		HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -842,7 +842,7 @@
 	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
 
 #ifdef CONFIG_BLK_DEV_TRITON
-	if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
 		printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
 		HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
@@ -1182,7 +1182,7 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
-	return clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.36/linux/drivers/block/ide-probe.c	Sat Jan 25 10:51:17 1997
+++ linux/drivers/block/ide-probe.c	Mon May 12 10:35:39 1997
@@ -47,7 +47,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
@@ -58,6 +57,7 @@
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/delay.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.1.36/linux/drivers/block/ide-tape.c	Fri Apr  4 08:52:17 1997
+++ linux/drivers/block/ide-tape.c	Mon May 12 17:39:50 1997
@@ -1777,7 +1777,7 @@
 		return;
 	}
 #ifdef CONFIG_BLK_DEV_TRITON
-	if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
 		HWIF(drive)->dmaproc(ide_dma_off, drive);
@@ -1916,7 +1916,7 @@
 	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
 
 #ifdef CONFIG_BLK_DEV_TRITON
-	if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
 		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
 		HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
@@ -2248,7 +2248,7 @@
 	status.all = GET_STAT();
 	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
 		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2506,7 +2506,7 @@
 	if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4)
 		idetape_insert_pipeline_into_queue (drive);
 
-	if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3254,7 +3254,7 @@
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	idetape_create_read_position_cmd (&pc);
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.36/linux/drivers/block/ide.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/ide.c	Mon May 12 10:35:39 1997
@@ -294,7 +294,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
@@ -307,6 +306,8 @@
 #include <linux/malloc.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -2144,7 +2145,7 @@
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
  */
-static int stridx (const char *s, char c)
+__initfunc(static int stridx (const char *s, char c))
 {
 	char *i = strchr(s, c);
 	return (i && c) ? i - s : -1;
@@ -2162,7 +2163,7 @@
  *     and base16 is allowed when prefixed with "0x".
  * 4. otherwise, zero is returned.
  */
-static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals))
 {
 	static const char *decimal = "0123456789";
 	static const char *hex = "0123456789abcdef";
@@ -2261,7 +2262,7 @@
  * "ide0=ali14xx"	: probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
  * "ide0=umc8672"	: probe/support umc8672 chipsets
  */
-void ide_setup (char *s)
+__initfunc(void ide_setup (char *s))
 {
 	int i, vals[3];
 	ide_hwif_t *hwif;
@@ -2558,7 +2559,7 @@
  * ide_probe_pci() scans PCI for a specific vendor/device function,
  * and invokes the supplied init routine for each instance detected.
  */
-static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj)
+__initfunc(static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj))
 {
 	unsigned long flags;
 	unsigned index;
@@ -2581,7 +2582,7 @@
  * This routine should ideally be using pcibios_find_class() to find all
  * PCI IDE interfaces, but that function causes some systems to "go weird".
  */
-static void probe_for_hwifs (void)
+__initfunc(static void probe_for_hwifs (void))
 {
 #ifdef CONFIG_PCI
 	/*
@@ -2620,7 +2621,7 @@
 #endif
 }
 
-void ide_init_builtin_drivers (void)
+__initfunc(void ide_init_builtin_drivers (void))
 {
 	/*
 	 * Probe for special "known" interface chipsets
@@ -2889,7 +2890,7 @@
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
-int ide_init (void)
+__initfunc(int ide_init (void))
 {
 	init_ide_data ();
 
@@ -2904,7 +2905,7 @@
 char *options = NULL;
 MODULE_PARM(options,"s");
 
-static void parse_options (char *line)
+__initfunc(static void parse_options (char *line))
 {
 	char *next = line;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/linear.c linux/drivers/block/linear.c
--- v2.1.36/linux/drivers/block/linear.c	Fri Nov 22 06:07:23 1996
+++ linux/drivers/block/linear.c	Mon May 12 10:35:39 1997
@@ -21,6 +21,7 @@
 
 #include <linux/md.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include "linear.h"
 
@@ -180,7 +181,7 @@
 
 #ifndef MODULE
 
-void linear_init (void)
+__initfunc(void linear_init (void))
 {
   register_md_personality (LINEAR, &linear_personality);
 }
diff -u --recursive --new-file v2.1.36/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.36/linux/drivers/block/loop.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/block/loop.c	Mon May 12 10:35:39 1997
@@ -23,6 +23,7 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/major.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -537,8 +538,8 @@
 #define loop_init init_module
 #endif
 
-int
-loop_init( void ) {
+__initfunc(int
+loop_init( void )) {
 	int	i;
 
 	if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
diff -u --recursive --new-file v2.1.36/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.1.36/linux/drivers/block/md.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/block/md.c	Mon May 12 10:35:39 1997
@@ -35,6 +35,7 @@
 #include <linux/kerneld.h>
 #endif
 #include <linux/errno.h>
+#include <linux/init.h>
 
 #define MAJOR_NR MD_MAJOR
 #define MD_DRIVER
@@ -546,7 +547,7 @@
 void raid1_init (void);
 void raid5_init (void);
 
-int md_init (void)
+__initfunc(int md_init (void))
 {
   printk ("md driver %s MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_VERSION, MAX_MD_DEV, MAX_REAL);
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.1.36/linux/drivers/block/ps2esdi.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/block/ps2esdi.c	Mon May 12 10:35:39 1997
@@ -43,6 +43,7 @@
 #include <linux/ps2esdi.h>
 #include <linux/blk.h>
 #include <linux/mca.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -176,7 +177,7 @@
 };
 
 /* initialization routine called by ll_rw_blk.c   */
-int ps2esdi_init(void)
+__initfunc(int ps2esdi_init(void))
 {
 
 	/* register the device - pass the name, major number and operations
@@ -197,7 +198,7 @@
 }				/* ps2esdi_init */
 
 /* handles boot time command line parameters */
-void tp720_setup(char *str, int *ints)
+__initfunc(void tp720_setup(char *str, int *ints))
 {
 	/* no params, just sets the tp720esdi flag if it exists */
 
@@ -205,7 +206,7 @@
 	tp720esdi = 1;
 }
 
-void ed_setup(char *str, int *ints)
+__initfunc(void ed_setup(char *str, int *ints))
 {
 	int hdind = 0;
 
@@ -252,10 +253,9 @@
 }
 
 /* ps2 esdi specific initialization - called thru the gendisk chain */
-static void ps2esdi_geninit(struct gendisk *ignored)
+__initfunc(static void ps2esdi_geninit(struct gendisk *ignored))
 {
 	/*
-
 	   The first part contains the initialization code
 	   for the ESDI disk subsystem.  All we really do
 	   is search for the POS registers of the controller
@@ -386,7 +386,7 @@
 }				/* ps2esdi_geninit */
 
 
-static void ps2esdi_get_device_cfg(void)
+__initfunc(static void ps2esdi_get_device_cfg(void))
 {
 	u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.1.36/linux/drivers/block/rd.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/rd.c	Mon May 12 10:35:39 1997
@@ -51,9 +51,11 @@
 #include <linux/ioctl.h>
 #include <linux/fd.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/byteorder.h>
 
 extern void wait_for_keypress(void);
 
@@ -269,7 +271,7 @@
 };
 
 /* This is the registration and initialization section of the ramdisk driver */
-int rd_init(void)
+__initfunc(int rd_init(void))
 {
 	int		i;
 
@@ -334,8 +336,8 @@
  *	romfs
  * 	gzip
  */
-int
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
+__initfunc(int
+identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
 {
 	const int size = 512;
 	struct minix_super_block *minixsb;
@@ -440,7 +442,7 @@
 /*
  * This routine loads in the ramdisk image.
  */
-static void rd_load_image(kdev_t device,int offset)
+__initfunc(static void rd_load_image(kdev_t device,int offset))
 {
 	struct inode inode, out_inode;
 	struct file infile, outfile;
@@ -527,7 +529,7 @@
 }
 
 
-void rd_load()
+__initfunc(void rd_load(void))
 {
 	if (rd_doload == 0)
 		return;
@@ -549,7 +551,7 @@
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void initrd_load(void)
+__initfunc(void initrd_load(void))
 {
 	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
 }
@@ -608,21 +610,21 @@
 
 #include "../../lib/inflate.c"
 
-static void *malloc(int size)
+__initfunc(static void *malloc(int size))
 {
 	return kmalloc(size, GFP_KERNEL);
 }
 
-static void free(void *where)
+__initfunc(static void free(void *where))
 {
 	kfree(where);
 }
 
-static void gzip_mark(void **ptr)
+__initfunc(static void gzip_mark(void **ptr))
 {
 }
 
-static void gzip_release(void **ptr)
+__initfunc(static void gzip_release(void **ptr))
 {
 }
 
@@ -631,7 +633,7 @@
  * Fill the input buffer. This is called only when the buffer is empty
  * and at least one byte is really needed.
  */
-static int fill_inbuf()
+__initfunc(static int fill_inbuf(void))
 {
 	if (exit_code) return -1;
 	
@@ -648,7 +650,7 @@
  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  * (Used for the decompressed data only.)
  */
-static void flush_window()
+__initfunc(static void flush_window(void))
 {
     ulg c = crc;         /* temporary variable */
     unsigned n;
@@ -666,14 +668,14 @@
     outcnt = 0;
 }
 
-static void error(char *x)
+__initfunc(static void error(char *x))
 {
 	printk(KERN_ERR "%s", x);
 	exit_code = 1;
 }
 
-static int
-crd_load(struct file * fp, struct file *outfp)
+__initfunc(static int
+crd_load(struct file * fp, struct file *outfp))
 {
 	int result;
 	
diff -u --recursive --new-file v2.1.36/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.1.36/linux/drivers/block/xd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/block/xd.c	Mon May 12 10:35:39 1997
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -126,7 +127,7 @@
 static u_short xd_iobase = 0;
 
 /* xd_init: register the block device number and set up pointer tables */
-int xd_init (void)
+__initfunc(int xd_init (void))
 {
 	if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 		printk("xd_init: unable to get major number %d\n",MAJOR_NR);
@@ -141,7 +142,7 @@
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char xd_detect (u_char *controller, unsigned int *address)
+__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address))
 {
 	u_char i,j,found = 0;
 
@@ -164,7 +165,7 @@
 
 /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 /* and set up the "raw" device entries in the table */
-static void xd_geninit (struct gendisk *ignored)
+__initfunc(static void xd_geninit (struct gendisk *ignored))
 {
 	u_char i,controller;
 	unsigned int address;
@@ -527,7 +528,7 @@
 	return (csb & CSB_ERROR);
 }
 
-static u_char xd_initdrives (void (*init_drive)(u_char drive))
+__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive)))
 {
 	u_char cmdblk[6],i,count = 0;
 
@@ -541,7 +542,7 @@
 	return (count);
 }
 
-static void xd_dtc_init_controller (unsigned int address)
+__initfunc(static void xd_dtc_init_controller (unsigned int address))
 {
 	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
@@ -556,7 +557,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void xd_dtc_init_drive (u_char drive)
+__initfunc(static void xd_dtc_init_drive (u_char drive))
 {
 	u_char cmdblk[6],buf[64];
 
@@ -581,7 +582,7 @@
 		printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
 }
 
-static void xd_wd_init_controller (unsigned int address)
+__initfunc(static void xd_wd_init_controller (unsigned int address))
 {
 	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
@@ -600,7 +601,7 @@
 	/* outb(0,XD_RESET); */		/* reset the controller */
 }
 
-static void xd_wd_init_drive (u_char drive)
+__initfunc(static void xd_wd_init_drive (u_char drive))
 {
 	u_char cmdblk[6],buf[0x200];
 
@@ -622,7 +623,7 @@
 		printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);	
 }
 
-static void xd_seagate_init_controller (unsigned int address)
+__initfunc(static void xd_seagate_init_controller (unsigned int address))
 {
 	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
@@ -639,7 +640,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void xd_seagate_init_drive (u_char drive)
+__initfunc(static void xd_seagate_init_drive (u_char drive))
 {
 	u_char cmdblk[6],buf[0x200];
 
@@ -655,7 +656,7 @@
 }
 
 /* Omti support courtesy Dirk Melchers */
-static void xd_omti_init_controller (unsigned int address)
+__initfunc(static void xd_omti_init_controller (unsigned int address))
 {
 	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
@@ -673,7 +674,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-static void xd_omti_init_drive (u_char drive)
+__initfunc(static void xd_omti_init_drive (u_char drive))
 {
 	/* gets infos from drive */
 	xd_override_init_drive(drive);
@@ -684,7 +685,7 @@
 
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-static void xd_override_init_drive (u_char drive)
+__initfunc(static void xd_override_init_drive (u_char drive))
 {
 	u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 	u_char cmdblk[6],i;
@@ -707,7 +708,7 @@
 }
 
 /* xd_setup: initialise from command line parameters */
-void xd_setup (char *command,int *integers)
+__initfunc(void xd_setup (char *command,int *integers))
 {
 	xd_override = 1;
 
@@ -720,7 +721,7 @@
 }
 
 /* xd_setparam: set the drive characteristics */
-static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc))
 {
 	u_char cmdblk[14];
 
diff -u --recursive --new-file v2.1.36/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c
--- v2.1.36/linux/drivers/block/z2ram.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/z2ram.c	Mon May 12 10:35:39 1997
@@ -28,6 +28,7 @@
 #include <linux/major.h>
 #include <linux/malloc.h>
 #include <linux/blk.h>
+#include <linux/init.h>
 
 #if defined(MODULE)
 #include <linux/module.h>
@@ -282,8 +283,8 @@
         block_fsync             /* fsync */
 };
 
-int
-z2_init( void )
+__initfunc(int
+z2_init( void ))
 {
 
     if ( !MACH_IS_AMIGA )
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- v2.1.36/linux/drivers/cdrom/aztcd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/aztcd.c	Mon May 12 10:35:39 1997
@@ -166,6 +166,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/major.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -1049,7 +1050,7 @@
   Kernel Interface Functions
   ##########################################################################
 */
-void aztcd_setup(char *str, int *ints)
+__initfunc(void aztcd_setup(char *str, int *ints))
 {  if (ints[0] > 0)
       azt_port = ints[1];
    if (ints[0] > 1)
@@ -1567,7 +1568,7 @@
  * Test for presence of drive and initialize it.  Called at boot time.
  */
 
-int aztcd_init(void)
+__initfunc(int aztcd_init(void))
 {       long int count, max_count;
 	unsigned char result[50];
 	int st;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/bpcd.c linux/drivers/cdrom/bpcd.c
--- v2.1.36/linux/drivers/cdrom/bpcd.c	Sun Jan 26 02:07:11 1997
+++ linux/drivers/cdrom/bpcd.c	Mon May 12 10:35:39 1997
@@ -113,6 +113,7 @@
 #include <linux/delay.h>
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -201,7 +202,7 @@
    nybble value.  The following function initialises the table.
 */
 
-static	void init_nyb_map( void )
+__initfunc(static void init_nyb_map( void ))
 
 {	int	i, j;
 
@@ -212,7 +213,7 @@
 	}
 }
 
-int bpcd_init (void)	/* preliminary initialisation */
+__initfunc(int bpcd_init (void))	/* preliminary initialisation */
 
 {	init_nyb_map();
 
@@ -327,7 +328,7 @@
    syntax:	bpcd=base[,nybble[,rep]]
 */
 
-void    bpcd_setup(char *str, int *ints)
+__initfunc(void bpcd_setup(char *str, int *ints))
 
 {       if (ints[0] > 0) bp_base = ints[1];
         if (ints[0] > 1) bp_nybble = ints[2];
@@ -425,7 +426,7 @@
 	if (bp_mode == 2) { t2(1); t2(0x20); }
 }
 
-static int probe( int id )
+__initfunc(static int probe( int id ))
 
 {	int l, h, t;
 	int r = -1;
@@ -588,7 +589,7 @@
 	bp_atapi(ej_cmd,0,"eject");
 }
 
-static int bp_reset( void )
+__initfunc(static int bp_reset( void ))
 
 /* the ATAPI standard actually specifies the contents of all 7 registers
    after a reset, but the specification is ambiguous concerning the last
@@ -615,7 +616,7 @@
 	return flg-1;	
 }
 
-static int bp_identify( char * id )
+__initfunc(static int bp_identify( char * id ))
 
 {	int k;
 	char   id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
@@ -627,7 +628,7 @@
 	return 0;
 }
 
-static int bp_port_check( void ) 	/* check for 8-bit port */
+__initfunc(static int bp_port_check( void )) 	/* check for 8-bit port */
 
 {	int	r;
 
@@ -640,7 +641,7 @@
 	return 0;
 }
 
-static int bp_locate( void )
+__initfunc(static int bp_locate( void ))
 
 {	int	k;
 
@@ -652,7 +653,7 @@
 	return -1;
 }
 
-static int bp_do_detect( int autop )
+__initfunc(static int bp_do_detect( int autop ))
 
 {	char   id[18];
 
@@ -705,7 +706,7 @@
    add it here ....
 */
 
-static int bp_detect( void )
+__initfunc(static int bp_detect( void ))
 
 {	if (bp_base) return bp_do_detect(0);
 	if (!bp_do_detect(0x378)) return 0;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cdi.c linux/drivers/cdrom/cdi.c
--- v2.1.36/linux/drivers/cdrom/cdi.c	Tue Feb 13 00:30:25 1996
+++ linux/drivers/cdrom/cdi.c	Mon May 12 10:35:39 1997
@@ -28,6 +28,7 @@
 
 #include <linux/config.h>
 #include <linux/blk.h>  /* where the proto type of cdi_init() is */
+#include <linux/init.h>
 #ifdef CONFIG_ISP16_CDI
 #include <linux/isp16.h>
 #endif CONFIG_ISP16_CDI
@@ -35,8 +36,8 @@
 /*
  *  Cdrom interface configuration.
  */
-int
-cdi_init(void)
+__initfunc(int
+cdi_init(void))
 {
   int ret_val = -1;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.1.36/linux/drivers/cdrom/cdu31a.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/cdu31a.c	Mon May 12 10:35:39 1997
@@ -190,6 +190,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -220,7 +221,7 @@
    unsigned short base;         /* I/O Base Address */
    short          int_num;      /* Interrupt Number (-1 means scan for it,
                                    0 means don't use) */
-} cdu31a_addresses[] =
+} cdu31a_addresses[] __initdata =
 {
 #if 0	/* No autoconfig any more. See Note at beginning
 	   of this file. */
@@ -2963,12 +2964,12 @@
 
 
 /* The different types of disc loading mechanisms supported */
-static const char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
+static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" };
 
-static void
+__initfunc(static void
 get_drive_configuration(unsigned short base_io,
                         unsigned char res_reg[],
-                        unsigned int *res_size)
+                        unsigned int *res_size))
 {
    int retry_count;
 
@@ -3032,9 +3033,9 @@
 /*
  * Set up base I/O and interrupts, called from main.c.
  */
-void
+__initfunc(void
 cdu31a_setup(char *strings,
-	     int  *ints)
+	     int  *ints))
 {
    if (ints[0] > 0)
    {
@@ -3063,8 +3064,8 @@
 /*
  * Initialize the driver.
  */
-int
-cdu31a_init(void)
+__initfunc(int
+cdu31a_init(void))
 {
    struct s_sony_drive_config drive_config;
    unsigned int res_size;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v2.1.36/linux/drivers/cdrom/cm206.c	Fri Dec 27 02:03:20 1996
+++ linux/drivers/cdrom/cm206.c	Mon May 12 10:35:39 1997
@@ -138,6 +138,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <linux/ucdrom.h>
 
@@ -1186,7 +1187,7 @@
    check_region, 15 bits of one port and 6 of another make things
    likely enough to accept the region on the first hit...
  */
-int probe_base_port(int base)
+__initfunc(int probe_base_port(int base))
 {
   int b=0x300, e=0x370;		/* this is the range of start addresses */
   volatile int fool, i;
@@ -1206,7 +1207,7 @@
 
 #if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
 /* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-int probe_irq(int nr) {
+__initfunc(int probe_irq(int nr)) {
   int irqs, irq;
   outw(dc_normal | READ_AHEAD, r_data_control);	/* disable irq-generation */
   sti(); 
@@ -1220,7 +1221,7 @@
 }
 #endif
 
-int cm206_init(void)
+__initfunc(int cm206_init(void))
 {
   uch e=0;
   long int size=sizeof(struct cm206_struct);
@@ -1303,7 +1304,7 @@
 
 static int cm206[2] = {0,0};	/* for compatible `insmod' parameter passing */
 
-void parse_options(void) 
+__initfunc(void parse_options(void))
 {
   int i;
   for (i=0; i<2; i++) {
@@ -1337,7 +1338,7 @@
 
 /* This setup function accepts either `auto' or numbers in the range
  * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */
-void cm206_setup(char *s, int *p)
+__initfunc(void cm206_setup(char *s, int *p))
 {
   int i;
   if (!strcmp(s, "auto")) auto_probe=1;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.1.36/linux/drivers/cdrom/gscd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/gscd.c	Mon May 12 10:35:39 1997
@@ -55,6 +55,7 @@
 #include <linux/ioport.h>
 #include <linux/major.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -191,7 +192,7 @@
 }
 
 
-void gscd_setup (char *str, int *ints)
+__initfunc(void gscd_setup (char *str, int *ints))
 {
   if (ints[0] > 0) 
   {
@@ -848,7 +849,7 @@
      return;
 }
 
-int find_drives (void)
+__initfunc(int find_drives (void))
 {
 int *pdrv;
 int drvnum;
@@ -899,7 +900,7 @@
     return drvnum;
 }    
 
-void init_cd_drive ( int num )
+__initfunc(void init_cd_drive ( int num ))
 {
 char resp [50];
 int  i;
@@ -991,7 +992,7 @@
 
 
 /* Test for presence of drive and initialize it.  Called only at boot time. */
-int gscd_init (void)
+__initfunc(int gscd_init (void))
 {
    return my_gscd_init ();
 }
@@ -999,7 +1000,7 @@
 
 /* This is the common initialisation for the GoldStar drive. */
 /* It is called at boot time AND for module init.           */
-int my_gscd_init (void)
+__initfunc(int my_gscd_init (void))
 {
 int i;
 int result;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c
--- v2.1.36/linux/drivers/cdrom/isp16.c	Sun Feb  2 05:18:30 1997
+++ linux/drivers/cdrom/isp16.c	Mon May 12 10:35:39 1997
@@ -48,6 +48,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/isp16.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 static short isp16_detect(void);
@@ -76,8 +77,8 @@
 #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
 
 
-void
-isp16_setup(char *str, int *ints)
+__initfunc(void
+isp16_setup(char *str, int *ints))
 {
   if ( ints[0] > 0 )
     isp16_cdrom_base = ints[1];
@@ -93,8 +94,8 @@
  *  ISP16 initialisation.
  *
  */
-int
-isp16_init(void)
+__initfunc(int
+isp16_init(void))
 {
   u_char expected_drive;
 
@@ -143,8 +144,8 @@
   return(0);
 }
 
-static short
-isp16_detect(void)
+__initfunc(static short
+isp16_detect(void))
 {
 
   if ( isp16_c929__detect() >= 0 )
@@ -153,8 +154,8 @@
     return(isp16_c928__detect());
 }
 
-static short
-isp16_c928__detect(void)
+__initfunc(static short
+isp16_c928__detect(void))
 {
   u_char ctrl;
   u_char enable_cdrom;
@@ -202,8 +203,8 @@
   return(i);
 }
 
-static short
-isp16_c929__detect(void)
+__initfunc(static short
+isp16_c929__detect(void))
 {
   u_char ctrl;
   u_char tmp;
@@ -229,8 +230,8 @@
   return(2);
 }
 
-static short
-isp16_cdi_config(int base, u_char drive_type, int irq, int dma)
+__initfunc(static short
+isp16_cdi_config(int base, u_char drive_type, int irq, int dma))
 {
   u_char base_code;
   u_char irq_code;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.1.36/linux/drivers/cdrom/mcd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/mcd.c	Mon May 12 10:35:39 1997
@@ -80,6 +80,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 /* #define REALLY_SLOW_IO  */
 #include <asm/system.h>
@@ -196,7 +197,7 @@
 static int getValue(unsigned char *result);
 
 
-void mcd_setup(char *str, int *ints)
+__initfunc(void mcd_setup(char *str, int *ints))
 {
    if (ints[0] > 0)
       mcd_port = ints[1];
@@ -1175,7 +1176,7 @@
  * Test for presence of drive and initialize it.  Called at boot time.
  */
 
-int mcd_init(void)
+__initfunc(int mcd_init(void))
 {
 	int count;
 	unsigned char result[3];
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v2.1.36/linux/drivers/cdrom/mcdx.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/mcdx.c	Mon May 12 10:35:39 1997
@@ -63,6 +63,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -910,7 +911,7 @@
 	return 1;
 }
 
-void mcdx_setup(char *str, int *pi)
+__initfunc(void mcdx_setup(char *str, int *pi))
 {
 	if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
 	if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
@@ -1160,7 +1161,7 @@
 
 /* Support functions ************************************************/
 
-int mcdx_init(void)
+__initfunc(int mcdx_init(void))
 {
 	int drive;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v2.1.36/linux/drivers/cdrom/optcd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/optcd.c	Mon May 12 10:35:39 1997
@@ -65,6 +65,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 #define MAJOR_NR OPTICS_CDROM_MAJOR
@@ -1961,7 +1962,7 @@
 
 /* Returns 1 if a drive is detected with a version string
    starting with "DOLPHIN". Otherwise 0. */
-static int version_ok(void)
+__initfunc(static int version_ok(void))
 {
 	char devname[100];
 	int count, i, ch, status;
@@ -2016,7 +2017,7 @@
 
 
 /* Get kernel parameter when used as a kernel driver */
-void optcd_setup(char *str, int *ints)
+__initfunc(void optcd_setup(char *str, int *ints))
 {
 	if (ints[0] > 0)
 		optcd_port = ints[1];
@@ -2024,7 +2025,7 @@
 
 /* Test for presence of drive and initialize it. Called at boot time
    or during module initialisation. */
-int optcd_init(void)
+__initfunc(int optcd_init(void))
 {
 	int status;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.1.36/linux/drivers/cdrom/sbpcd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/sbpcd.c	Mon May 12 10:35:39 1997
@@ -328,6 +328,7 @@
 #include <linux/major.h> 
 #include <linux/string.h>
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -3052,7 +3053,7 @@
 }
 #endif FUTURE
 /*==========================================================================*/
-static void check_datarate(void)
+__initfunc(static void check_datarate(void))
 {
 	int i=0;
 	
@@ -3122,7 +3123,7 @@
 }
 #endif
 /*==========================================================================*/
-static void ask_mail(void)
+__initfunc(static void ask_mail(void))
 {
 	int i;
 	
@@ -3141,7 +3142,7 @@
 	msg(DBG_INF,"infobuf =%s\n", msgbuf);
 }
 /*==========================================================================*/
-static int check_version(void)
+__initfunc(static int check_version(void))
 {
 	int i, j, l;
 	int teac_possible=0;
@@ -3439,7 +3440,7 @@
 /*
  * probe for the presence of an interface card
  */
-static int check_card(int port)
+__initfunc(static int check_card(int port))
 {
 #undef N_RESPO
 #define N_RESPO 20
@@ -3543,7 +3544,7 @@
 /*
  * probe for the presence of drives on the selected controller
  */
-static int check_drives(void)
+__initfunc(static int check_drives(void))
 {
 	int i, j;
 	
@@ -5285,9 +5286,10 @@
  *
  */
 #if (SBPCD_ISSUE-1)
-static
+__initfunc(static void sbpcd_setup(const char *s, int *p))
+#else
+__initfunc(void sbpcd_setup(const char *s, int *p))
 #endif
-void sbpcd_setup(const char *s, int *p)
 {
 	setup_done++;
 	msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
@@ -5338,7 +5340,7 @@
  *        port 0x330, we have to use an offset of 8; so, the real CDROM port
  *        address is 0x338.
  */
-static int config_spea(void)
+__initfunc(static int config_spea(void))
 {
 	/*
          * base address offset between configuration port and CDROM port,
@@ -5397,7 +5399,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-int SBPCD_INIT(void)
+__initfunc(int SBPCD_INIT(void))
 #endif MODULE
 {
 	int i=0, j=0;
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.1.36/linux/drivers/cdrom/sjcd.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/sjcd.c	Mon May 12 10:35:39 1997
@@ -65,6 +65,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/major.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -159,7 +160,7 @@
  * Set up device, i.e., use command line data to set
  * base address.
  */
-void sjcd_setup( char *str, int *ints )
+__initfunc(void sjcd_setup( char *str, int *ints ))
 {
    if (ints[0] > 0)
       sjcd_base = ints[1];
@@ -1449,7 +1450,7 @@
  * Test for presence of drive and initialize it. Called at boot time.
  * Probe cdrom, find out version and status.
  */
-int sjcd_init( void ){
+__initfunc(int sjcd_init( void )){
   int i;
 
   printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.1.36/linux/drivers/cdrom/sonycd535.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/sonycd535.c	Mon May 12 10:35:39 1997
@@ -120,6 +120,7 @@
 #include <linux/genhd.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #define REALLY_SLOW_IO
 #include <asm/system.h>
@@ -1484,8 +1485,8 @@
 /*
  * Initialize the driver.
  */
-int
-sony535_init(void)
+__initfunc(int
+sony535_init(void))
 {
 	struct s535_sony_drive_config drive_config;
 	Byte cmd_buff[3];
@@ -1649,8 +1650,8 @@
  *
  * the address value has to be the existing CDROM port address.
  */
-void
-sonycd535_setup(char *strings, int *ints)
+__initfunc(void
+sonycd535_setup(char *strings, int *ints))
 {
 	/* if IRQ change and default io base desired,
 	 * then call with io base of 0
diff -u --recursive --new-file v2.1.36/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.36/linux/drivers/char/Config.in	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/Config.in	Mon May 12 10:35:39 1997
@@ -19,7 +19,10 @@
 fi
 bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
 if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
-   tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+   tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+   if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+      tristate 'Digiboard PC/Xx Support' CONFIG_DIGI
+   fi
    tristate 'Cyclades async mux support' CONFIG_CYCLADES
    bool 'Stallion multiport serial support' CONFIG_STALDRV
    if [ "$CONFIG_STALDRV" = "y" ]; then
diff -u --recursive --new-file v2.1.36/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.36/linux/drivers/char/Makefile	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/Makefile	Mon May 12 10:35:39 1997
@@ -61,6 +61,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_DIGIEPCA),y)
+L_OBJS += epca.o
+else
+  ifeq ($(CONFIG_DIGIEPCA),m)
+  M_OBJS += epca.o
+  endif
+endif
+
 ifeq ($(CONFIG_CYCLADES),y)
 L_OBJS += cyclades.o
 else
diff -u --recursive --new-file v2.1.36/linux/drivers/char/README.epca linux/drivers/char/README.epca
--- v2.1.36/linux/drivers/char/README.epca	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/README.epca	Mon May 12 10:35:39 1997
@@ -0,0 +1,506 @@
+user.doc
+Digi International driver package for the PC/Xe, PC/Xi, PC/Xr, PC/Xem as well
+the EISA and PCI variants of these boards where applicable.
+Copyright (C) 1996 Digi International.  Written by Ronnie Sanford digilnux@dgii.com
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2 of the License, or (At your
+   option) any later version.
+
+   This 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. 
+
+
+This document describes the software used with the Digi/Linux driver package.
+The four user programs listed below are described in this document:
+
+  1.  digiConfig   -> Application that configures the Digi driver.
+
+  2.  digiDload    -> Application which initializes the Digi hardware.
+
+  3.  buildPCI     -> Application which provides the user a method of
+                      building device nodes for PCI devices. 
+
+  4.  ditty        -> Application which provides the user a method of
+                      configuring terminal options on Digi hardware.
+
+
+
+--------------------------------------------------------------------------
+1.  Configuring driver/kernel for Digi products
+--------------------------------------------------------------------------
+
+   The Digi driver must be configured each time Digi hardware is added
+   or removed.  There are two supported methods of doing this.  The
+   first method configures the driver dynamically at boot time but requires
+   the user to utilize the lilo loader.  This method is the preffered method
+   as it does not require the rebuilding of the kernel.  In order to use lilo
+   to configure Digi boards at boot time an appropriate append command should
+   be added to /etc/lilo.conf below the appropriate label decleration.  
+   See footer 4.  The append commands format is a string of comma seperated
+   identifiers or integers used to configure supported boards.  These six
+   values in order are:
+
+     Enable/Disable this card or Override,
+     Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2),
+                   EISA/Xem (3), PC/Xe (64K) (4), PC/Xi (5).
+     Enable/Disable alternate pin arrangement,
+     Number of ports on this card,
+     I/O Port where card is configured (in HEX if using string identifiers),
+     Base of memory window (in HEX if using string identifiers) 
+
+   A sample append command is given below which if used would configure and 
+   enable a PC/Xe with 8 ports, at i/o address 200, memory address 0xd0000 
+   with alt pin turned off.  The lilo.conf file should look like this:
+
+     image = /vmlinuz
+       root = /dev/hda2
+       label = vmlinuz
+       append="digiepca=E,PC/Xe,D,8,200,D0000"
+
+   likewise the below will perform the same function:
+
+     image = /vmlinuz
+       root = /dev/hda2
+       label = vmlinuz
+       append="digiepca=1,0,0,8,512,851968"
+
+   Note:
+
+     PCI boards are auto-detected and configured (Hence their codes are
+     not given here).  Do not attempt to configure PCI boards with the lilo 
+     append command.
+
+     If configuration data has been specified by using digiConfig (Described
+     below), and you wish to override this configuration using lilo without
+     specifying a specific card (Example if there are PCI cards in the system)
+     the following override command will accomplish this:
+
+     -> append="digiepca=2"
+   
+   If lilo is not enabled, the second method of configuring Digi hardware 
+   will have to be used.  digiConfig is an application that can be used 
+   to inform the system of any additions, deletions, or modifications
+   involving Digi hardware.  To use this method the operator executes  
+   digiConfig anytime an EISA or ISA card is added that he wishes to use. 
+   This routine is also used to remove cards from the system, and to modify 
+   parameters of those cards already present in the system.  Upon being 
+   executed digiConfig modifies files accessed by the Digi driver.  To make 
+   these changes permanent; the operating system must be recompiled.  After 
+   the operating system has been recompiled and booted, the changes made with
+   digiConfig will be introduced to the user.  This program MUST be executed
+   every time Digi EISA/ISA hardware configuration changes.  Note, it is not
+   necessary to execute digiConfig in order to configure the Digi PCI cards.
+   These cards are self-identifying and will be recognized by the driver.  
+   They cannot be displayed using digiConfig nor will digiConfig build the 
+   device nodes their device nodes. See footer 1.
+
+   To execute digiConfig; simply type: digiConfig
+
+   The application will query you for the type, memory address, port 
+   address, number of ports, alt pin disposition and status of each board
+   that exist on the system.  Note, currently this driver only supports 
+   PC/Xe, PC/Xeve, PC/Xi, PC/Xr, and PC/Xem as well as their EISA and PCI 
+   implementations if applicable.  All supported cards (Other than PCI) that
+   are present should be registered via digiConfig.  See footer 2.
+
+   After all cards have been configured select exit.  The system will then
+   inform you if any changes have been made, and ask you if it is okay to
+   make these changes permanent.  If the data entered is correct, select okay.
+   Selecting cancel will prevent the changes from becoming active.  digiConfig
+   can then be re-executed to configure the system again.
+
+--------------------------------------------------------------------------
+2.  Initializing Digi hardware with digiDload
+--------------------------------------------------------------------------
+
+   digiDload is the application executed after the Digi driver has been
+   loaded.  It is responsible for initializing the hardware and leaving
+   it in a state such that the Digi board may be operated by the user.
+   The application may be placed anywhere on the path, but its related
+   support files must be located in /etc/digi.  The related files are:
+
+         sxfep.bin
+         sxbios.bin
+         xxfep.bin
+         xxbios.bin
+
+   The format for this command is "digiDload [v]".  If given the "v"
+   option turns on verbosity.  If not given the application runs in quite
+   mode.  To execute the program simply type:
+
+        digiDload 
+
+   Upon completion digiDload will generate the below message:
+
+        "digiDload complete: Card initialized"
+
+   At this point the card is configured and ready for normal usage.  See
+   technotes.doc for information on how how ports are determined and 
+   assigned.
+
+--------------------------------------------------------------------------
+3.  Build PCI device nodes with buildPCI 
+--------------------------------------------------------------------------
+
+   buildPCI is an application useful for building the necessary device nodes
+   for Digi PCI cards.  It is reccomended that this tool be used because the
+   current digiConfig application does not provide this function for PCI cards
+   (Though it does build device nodes for non-PCI cards).  To use this program
+   execute the following:first install the driver, and execute digiDload (See above).  After digiDload
+   has sucessfully loaded, execute the following:
+
+        buildPCI <arg1> <arg2>
+
+   Where arg1 is the number of ports connected to Digi cards that are not PCI 
+   (As shown by the digiConfig utility), and arg2 is the number of ports 
+   connected to Digi cards that are PCI.
+
+   Note, buildPCI only has to be ran once to build the necessary device 
+   nodes.  Though this program may be executed at anytime, we reccomend 
+   delaying execution until the first time you install the package and after 
+   digiDload has been executed.
+
+--------------------------------------------------------------------------
+4.  Setting Terminal Options with ditty
+--------------------------------------------------------------------------
+
+ditty is a utility program that sets and displays the terminal options 
+for Digi intelligent serial products.  See man ditty for detailed information.
+
+
+Footnotes:
+
+1.  The 1.2.x kernel does not provide a method of mapping the high 
+    addresses (Normally higher than RAM) associated with PCI.  For this
+    reason, this driver disables PCI support while running under the 1.2.x
+    kernels.
+
+2.  PCI cards should not and cannot be registered with digiConfig.  After
+    the driver has been loaded buildPCI may be executed to construct the 
+    necessary device nodes.  This step is not necessary for system not 
+    having Digi PCI cards.
+
+3.  This is because we forsee a time when buildPCI may auto-detect the
+    available Digi PCI cards and this would only work if the program is 
+    executed after digiDload.
+
+4.  A complete example is given in install.doc.
+
+-------------CHANGES--------------------
+
+All changes should be recorded here.  All changes should be explained in 
+verbose detail.  
+-----------------------------------------------------------------------
+Programmer            : Ronnie Sanford
+Date                  : June 1, 1996
+Description (Verbose) : Initial release of driver package.
+Files affected        : all
+Release version       : 1.0.0f  (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer            : Ronnie Sanford
+Date                  : August 7, 1996
+Description (Verbose) : Made several modifications to provide PCI and EISA
+                        support:
+
+                        1.  We now allocate the termios structures based on
+                            the maximum number of channels that COULD be 
+                            available to the system.  We no longer use the
+                            number of channels declared in epcaconfig.h 
+                            (NBDEVS) as the total channel number.  This is 
+                            because this value does not represent channels
+                            available to potential PCI cards.  This new 
+                            larger value is also passed back to the os in
+                            the num field of tty_driver. 
+
+                        2.  Added code to copy the previous board structure
+                            (Now called static_boards) into a new local 
+                            copy of the boards structure.  This has been 
+                            done so that PCI cards may be added to this 
+                            board array and later referenced (And even 
+                            queried.). 
+
+                        3.  Added code to pc_init that checks for supported
+                            PCI cards.  If found this code initializes a new
+                            entry into the drivers local board structure 
+                            with the PCI cards address, and type, etc..  It 
+                            also bumps the card count (num_cards).
+
+                        4.  Modified code in post_fep_init so that when this
+                            routine is executed the number of ports supported
+                            by a particular PCI card will be determined and
+                            loaded into the board structure.  It would be 
+                            much better if this code was placed in pc_init
+                            (Because we could then report to the os the true
+                            number of ports available; not just the max), but
+                            since the card has to be booted to determine the
+                            number of ports it supports, we are forced to do it
+                            after DIGI_INIT has called post_fep_init.  In the 
+                            future we may attempt to read the num ports 
+                            attached directly (address 0x1ac).
+
+                        5.  Added board types to epca.h in support of various
+                            PCI boards (Some of which do not exist yet).  
+                            Added procedures for these boards throughout the
+                            code.  Note, windowing is not necessary for PCI
+                            boards.  
+
+                        6.  Added code supporting the EISA/XEM.  This included
+                            modifying epca.h with the new board type and 
+                            adding this type into the driver.  The EISA/XEM
+                            is basically identical to the PC/XEM, other than
+                            it's base address does not have to be (And cannot
+                            be configured directly).
+
+                        7.  Modified digiConfig to prompt for EISA/XEM cards.
+                             
+Files affected        : epca.c, epca.h, digi1.h, digiConfig
+Release version       : 1.0.0g  (BETA)
+-----------------------------------------------------------------------
+-----------------------------------------------------------------------
+Programmer            : Ronnie Sanford
+Date                  : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+                        1.  A problem affecting hard flow control was found 
+                            in the termios2digi_h routine.  Specifically,
+                            when the user activated hard flow control using
+                            the CRTSCTS specification, the values used to 
+                            program hard flow control on the board were 
+                            incorrect.  The solution was to change a line
+                            that read "res |= ((ch->m_dtr) | (ch->m_rts));"
+                            to "res |= ((ch->m_cts) | (ch->m_rts));"  This 
+                            line only applies if cflag & CRTSCTS.  Special
+                            thanks to Matt Robinson (matt@mania.com.au) who
+                            found and fixed this problem.
+
+                        2.  In previous betas the cud device was set to  CLOCAL
+                            on driver boot up.  Likewise the ttyD device was
+                            set to ~CLOCAL.  This has been fixed in this driver.
+                            Now ttyD is CLOCAL and cud is ~CLOCAL.  The fix
+                            for this can be found in pc_init.
+
+                        3.  In ditty.c many changes were made to eliminate bugs
+                            and warning messages.  Two ioctl calls were eliminated
+                            as well a problem involving using the returned baud
+                            index to determine the drivers baud rate.  Newer 
+                            Linux kernels support higher baud rates by using
+                            0x1000 bit.  When the returned value (ored with
+                            0x1000) was used to reference our fbaud table a 
+                            serious memory problem occured.  This has been fixed.
+
+                        4.  Added a request_region call to post_fep_init.  This
+                            should cause the i/o ports being used to be 
+                            registered with proc.
+ 
+                        5.  Modified digiConfig to set all cud and ttyD devices
+                            to read/write all permission.
+
+                        6.  Developed a new apps called buildPCI that provides 
+                            an easy way to build device nodes for PCI cards.
+         
+                        7.  Modified user.doc and technotes.doc document the
+                            use of buildPCI.
+
+Files affected        : epca.c, ditty.c, digiConfig, user.doc, technotes.doc 
+Release version       : 1.0.0 (Official release)
+-----------------------------------------------------------------------
+Programmer            : Ronnie Sanford
+Date                  : August 21, 1996
+Description (Verbose) : Made the following modifications:
+
+                        1.  Removed code from pc_close which closes the 
+                            drivers line discipline and restores its original
+                            line discipline.  This is currently unecessary,
+                            though future fast cook enhancements may require
+                            this.
+
+                        2.  Removed code in block_til_ready that set the 
+                            asyncflags to either ASYNC_CALLOUT_ACTIVE, or
+                            ASYNC_NORMAL_ACTIVE.  This code was redundant
+                            as it already existed in block_til_ready.
+
+                        3.  Added code in block_til_ready to cause a return
+                            prior to schedule being called if the device 
+                            was a CALLOUT device.  CALLOUT devices never
+                            block on CD. (This was a serious bug that 
+                            prevented the CALLOUT devices (ttyD) from 
+                            functioning properly in some instances.
+
+                            Make a change in the MODEMCHG_IND case of doevent
+                            such that it does not require ASYNC_CALLOUT_ACTIVE
+                            or ASYNC_NORMAL_ACTIVE to be set in order to 
+                            unblock an open (Using wait_interruptible).
+
+                            Thanks to Mike McLagan (mike.mclagan@linux.org)
+                            for diagnosing and fixing this problem. 
+
+                        4.  Made changes to the disposition of CLOCAL on 
+                            both SERIAL NORMAL and CALLOUT devices.  Both
+                            device types now have CLOCAL active at default.
+                            This may be changed with a stty command.
+
+                        5.  Made changes to digiConfig such that it checks
+                            major.h (If valid) for the correct major
+                            numbers to use.
+
+Files affected        : epca.c, digiConfig 
+Release version       : 1.0.1a 
+
+
+-----------------------------------------------------------------------
+Programmer            : Ronnie Sanford
+Date                  : September 17, 1996
+Description (Verbose) : Made the following modifications:
+	
+                        1. Modified pc_open such that it no longer checks 
+                           the cflag value returned by termios2digi_c for
+                           CLOCAL.  Digi hardware does not use this value
+                           and thus termios2digi_c rightly screens this 
+                           value out.  This driver checks for CLOCAL using
+                           the drivers cflag value as known by the Linux OS.
+                           (The value passed into termios2digi_c)
+
+                        2. Modified termios2digi_c to screen out the 
+                           CBAUDEX in CBAUD.  This error caused parity to
+                           automaticaly be enabled on at higher baud rates.
+		
+
+                        3. Added the "disable_bh()" call to the shutdown
+                           subroutine.  Hopefully this will allow the driver
+                           to correctly clean up after itself when used as a
+                           module. 
+
+                        4. Added support for the PC/XI and 64K PC/XE cards.
+                           This involved primarily modifying digiDload to
+                           initialize and boot the new cards; however 
+                           driver modifications were also required to 
+                           provide the proper windowing for the newly 
+                           supported cards. (Code was also added to 
+                           determine the memory segment of the XI card as
+                           that card may have more than 64K.  Currently
+                           digiDload assumes a 64K XI card.)
+
+                        5. Added subroutine called epca_setup that can be 
+                           called during LILO boot up.  This provides the 
+                           user an easy way to change cards; without 
+                           running digiConfig and without recompiling the
+                           kernel.  Added code in pc_init and pc_open to
+                           support the epca_setup routine.  pc_init checks
+                           the liloconfig flag (Which is set by epca_setup)
+                           to determine if the driver is using the LILO 
+                           arguments.  If not pc_init loads the board data 
+                           found in epcaconfig.h; if so it DOESN'T load
+                           epcaconfig data depending on epca_setup to handle 
+                           board configuration.  pc_open has been modified 
+                           such that it checks to insure that no errors
+                           occured during the LILO boot process.  If a 
+                           user attempts to boot the driver (via. LILO)
+                           with incorrect data, the open will fail. 
+
+                        6. Modified the windowing routines pcxe_rxwinon
+                           and pcxe_txwinon routines.  A bug existed such
+                           that those routines checked to see if the rxwin 
+                           and txwin flags were reset.  If so they assumed 
+                           the board was an XI or 64K XE.  Furthermore since
+                           these flags were never initialized in our driver
+                           sometimes they were 0 and therefore caused a 
+                           memory fault (Or at least a window overrun).  This
+                           code has been removed since the pcxe shares 
+                           nothing in common with the 64K XI and XE. 
+
+                        7. Added code in pc_init to set the memory_seg for
+                           the various boards.  This code was necessary to
+                           correct a bug in the PCXE, PCXEVE code where 
+                           receive and transmit pointers were being calculated
+                           from an uninitialized variable (memory_seg). 
+
+                        8. Modified digiConfig to allow 64K PC/XI and 64K
+                           PC/XE cards to be configured.
+                           
+                        9. Made changes to support the new 2.1.x development 
+                           kernel.  In particular this required changing all
+                           references to vremap to ioremap. 
+
+                       10. Modified digiConfig such that it now generates 
+                           node names corresponding to their internal 
+                           as opposed to the label on the port itself.  Nodes
+                           (ttyD?? and cud??) now start at 0.  Example:
+                           ttyD0 and cud0 represent port 1 on any supported
+                           Digi product.  A similar change has been made
+                           in buildPCI.c. 
+
+                       12. At the early portion of post_fep_init if a PCI
+                           card is detected a warning message could be given
+                           incorrectly if 64 ports were attached to a PCI 
+                           card.  The below line :
+
+                           epcaassert(bd->numports > 64,"PCI returned a invalid number of ports"); 
+    
+                           was changed to :
+
+                           epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); 
+
+                           Remember that epcaassert checks for NOT true.
+                           Special thanks to Daniel Taylor for fixing this.
+
+                       13. Modified the epcaparam routine.  In version 100
+                           and 101a there was a line that looked like the 
+                           below:
+
+                             if (ch->omodem != mval)
+                           
+                           The problem with this line was that the first time
+                           through omodem was not initialized.  Secondly, since
+                           many TIOC commands did not alter mval (They use
+                           a different variable) changes made by these commands
+                           could be lost.  This line was changed to:
+
+                             mval ^= ch->modemfake & (mval ^ ch->modem);
+
+                             if (ch->omodem ^ mval)
+
+                       14. Modified digiConfig in such a way that it checks 
+                           the version number of the kernel and if it finds
+                           a 2.x.x kernel or higher it reads the necessary 
+                           major numbers for cud and ttyD devices from major.h.
+                           This was also done in prior versions but these
+                           versions required a #define which identified the 
+                           kernel as a version which did not have major numbers
+                           assigned to Digi systems.  This #define is no 
+                           longer required allowing the same source tree for
+                           multiple kernel releases.
+
+                       15. Used macros to replace kernel specific calls such
+                           as put_fs_long, get_fs_long, put_user, and get_user
+                           the kernel version is now detected and the macro
+                           is defined as to correspond with the kernel it
+                           is being compiled into.  Again this was done to
+                           allow one source tree for multiple kernel releases. 
+
+                       16. Added support for the new 2.1.x development kernels
+                           to digiInstall.
+
+Files affected        : epca.c, digiConfig 
+Release version       : 1.1.0
+-----------------------------------------------------------------------
+Programmer            : Daniel Taylor
+Date                  : April 25, 1997
+Description (Verbose) : Updated driver:
+                        1.  Fixed DCD bug. (&tq_scheduler)
+                        2.  Removed BH handler code, as it was only handling
+                            hangups, and not being called for that.
+                        3.  Namespace cleanup (DIGI_TIMER2 => DIGI_TIMER)
+                        4.  Updated to 2.1.36, removed #ifdefs for earlier
+                            kernel revisions.
+Files affected        : epca.c
+Release version       : 1.1.1  (BETA)
+-----------------------------------------------------------------------
diff -u --recursive --new-file v2.1.36/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.1.36/linux/drivers/char/busmouse.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/busmouse.c	Mon May 12 10:35:39 1997
@@ -56,7 +56,7 @@
 static struct mouse_status mouse;
 static int mouse_irq = MOUSE_IRQ;
 
-void bmouse_setup(char *str, int *ints)
+__initfunc(void bmouse_setup(char *str, int *ints))
 {
 	if (ints[0] > 0)
 		mouse_irq=ints[1];
diff -u --recursive --new-file v2.1.36/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.36/linux/drivers/char/console.c	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/console.c	Mon May 12 10:35:39 1997
@@ -101,6 +101,7 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
@@ -1979,7 +1980,7 @@
  * Reads the information preserved by setup.s to determine the current display
  * type and sets everything accordingly.
  */
-unsigned long con_init(unsigned long kmem_start)
+__initfunc(unsigned long con_init(unsigned long kmem_start))
 {
 	const char *display_desc = "????";
 	int currcons = 0;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v2.1.36/linux/drivers/char/consolemap.c	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/consolemap.c	Mon May 12 10:35:39 1997
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include "consolemap.h"
 
@@ -483,8 +484,8 @@
  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
  * from this function, hence the call from sys_setup.
  */
-void
-console_map_init(void)
+__initfunc(void
+console_map_init(void))
 {
   con_set_default_unimap();
 }
diff -u --recursive --new-file v2.1.36/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.36/linux/drivers/char/cyclades.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/cyclades.c	Mon May 12 10:35:39 1997
@@ -1,5 +1,7 @@
+#define BLOCKMOVE
 static char rcsid[] =
-"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $";
+"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $";
+
 /*
  *  linux/drivers/char/cyclades.c
  *
@@ -22,11 +24,128 @@
  * This module exports the following rs232 io functions:
  *   int cy_init(void);
  *   int cy_open(struct tty_struct *tty, struct file *filp);
+ * and the following functions for modularization.
+ *   int init_module(void);
+ *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
- * Revision 1.36.3.9  1996/10/07 19:47:13  bentson
- * add MOD_DEC_USE_COUNT in one return from cy_close (as
- * noted by Jon Lewis <jlewis@INORGANIC5.FDT.NET>)
+ * Revision 1.36.4.27  1997/03/26 10:30:00  daniel
+ * Changed for suport linux versions 2.1.X.
+ * Backward compatible with linux versions 2.0.X.
+ * Corrected illegal use of filler field in
+ * CH_CTRL struct.
+ * Deleted some debug messages.
+ *
+ * Revision 1.36.4.26  1997/02/27 12:00:00  daniel
+ * Included check for NULL tty pointer in cyz_poll.
+ *
+ * Revision 1.36.4.25  1997/02/26 16:28:30  bentson
+ * Bill Foster at Blarg! Online services noticed that
+ * some of the switch elements of -Z modem control
+ * lacked a closing "break;"
+ *
+ * Revision 1.36.4.24  1997/02/24 11:00:00  daniel
+ * Changed low water threshold for buffer xmit_buf
+ *
+ * Revision 1.36.4.23  1996/12/02 21:50:16  bentson
+ * Marcio provided fix to modem status fetch for -Z
+ *
+ * Revision 1.36.4.22  1996/10/28 22:41:17  bentson
+ * improve mapping of -Z control page (thanks to Steve
+ * Price <stevep@fa.tdktca.com> for help on this)
+ *
+ * Revision 1.36.4.21  1996/09/10 17:00:10  bentson
+ * shift from cpu-bound to memcopy in cyz_polling operation
+ *
+ * Revision 1.36.4.20  1996/09/09 18:30:32  Bentson
+ * Added support to set and report higher speeds.
+ *
+ * Revision 1.36.4.19c  1996/08/09 10:00:00  Marcio Saito
+ * Some fixes in the HW flow control for the BETA release.
+ * Don't try to register the IRQ.
+ *
+ * Revision 1.36.4.19  1996/08/08 16:23:18  Bentson
+ * make sure "cyc" appears in all kernel messages; all soft interrupts
+ * handled by same routine; recognize out-of-band reception; comment
+ * out some diagnostic messages; leave RTS/CTS flow control to hardware;
+ * fix race condition in -Z buffer management; only -Y needs to explictly
+ * flush chars; tidy up some startup messages;
+ *
+ * Revision 1.36.4.18  1996/07/25 18:57:31  bentson
+ * shift MOD_INC_USE_COUNT location to match
+ * serial.c; purge some diagnostic messages;
+ *
+ * Revision 1.36.4.17  1996/07/25 18:01:08  bentson
+ * enable modem status messages and fetch & process them; note
+ * time of last activity type for each port; set_line_char now
+ * supports more than line 0 and treats 0 baud correctly;
+ * get_modem_info senses rs_status;
+ *
+ * Revision 1.36.4.16  1996/07/20 08:43:15  bentson
+ * barely works--now's time to turn on
+ * more features 'til it breaks
+ *
+ * Revision 1.36.4.15  1996/07/19 22:30:06  bentson
+ * check more -Z board status; shorten boot message
+ *
+ * Revision 1.36.4.14  1996/07/19 22:20:37  bentson
+ * fix reference to ch_ctrl in startup; verify return
+ * values from cyz_issue_cmd and cyz_update_channel;
+ * more stuff to get modem control correct;
+ *
+ * Revision 1.36.4.13  1996/07/11 19:53:33  bentson
+ * more -Z stuff folded in; re-order changes to put -Z stuff
+ * after -Y stuff (to make changes clearer)
+ *
+ * Revision 1.36.4.12  1996/07/11 15:40:55  bentson
+ * Add code to poll Cyclom-Z.  Add code to get & set RS-232 control.
+ * Add code to send break.  Clear firmware ID word at startup (so
+ * that other code won't talk to inactive board).
+ *
+ * Revision 1.36.4.11  1996/07/09 05:28:29  bentson
+ * add code for -Z in set_line_char
+ *
+ * Revision 1.36.4.10  1996/07/08 19:28:37  bentson
+ * fold more -Z stuff (or in some cases, error messages)
+ * into driver; add text to "don't know what to do" messages.
+ *
+ * Revision 1.36.4.9  1996/07/08 18:38:38  bentson
+ * moved compile-time flags near top of file; cosmetic changes
+ * to narrow text (to allow 2-up printing); changed many declarations
+ * to "static" to limit external symbols; shuffled code order to
+ * coalesce -Y and -Z specific code, also to put internal functions
+ * in order of tty_driver structure; added code to recognize -Z
+ * ports (and for moment, do nothing or report error); add cy_startup
+ * to parse boot command line for extra base addresses for ISA probes;
+ *
+ * Revision 1.36.4.8  1996/06/25 17:40:19  bentson
+ * reorder some code, fix types of some vars (int vs. long),
+ * add cy_setup to support user declared ISA addresses
+ *
+ * Revision 1.36.4.7  1996/06/21 23:06:18  bentson
+ * dump ioctl based firmware load (it's now a user level
+ * program); ensure uninitialzed ports cannot be used
+ *
+ * Revision 1.36.4.6  1996/06/20 23:17:19  bentson
+ * rename vars and restructure some code
+ *
+ * Revision 1.36.4.5  1996/06/14 15:09:44  bentson
+ * get right status back after boot load
+ *
+ * Revision 1.36.4.4  1996/06/13 19:51:44  bentson
+ * successfully loads firmware
+ *
+ * Revision 1.36.4.3  1996/06/13 06:08:33  bentson
+ * add more of the code for the boot/load ioctls
+ *
+ * Revision 1.36.4.2  1996/06/11 21:00:51  bentson
+ * start to add Z functionality--starting with ioctl
+ * for loading firmware
+ *
+ * Revision 1.36.4.1  1996/06/10 18:03:02  bentson
+ * added code to recognize Z/PCI card at initialization; report
+ * presence, but card is not initialized (because firmware needs
+ * to be loaded)
  *
  * Revision 1.36.3.8  1996/06/07 16:29:00  bentson
  * starting minor number at zero; added missing verify_area
@@ -38,7 +157,7 @@
  * remove unused diagnostic statements; minor 0 is first;
  *
  * Revision 1.36.3.6  1996/03/13 13:21:17  marcio
- * The kernel function ioremap (available only in later 1.3.xx kernels)
+ * The kernel function vremap (available only in later 1.3.xx kernels)
  * allows the access to memory addresses above the RAM. This revision
  * of the driver supports PCI boards below 1Mb (device id 0x100) and
  * above 1Mb (device id 0x101).
@@ -261,6 +380,52 @@
  *
  */
 
+/* If you need to install more boards than NR_CARDS, change the constant
+   in the definition below. No other change is necessary to support up to
+   eight boards. Beyond that you'll have to extend cy_isa_addresses. */
+
+#define NR_CARDS        4
+
+/*
+   If the total number of ports is larger than NR_PORTS, change this
+   constant in the definition below. No other change is necessary to
+   support more boards/ports. */
+
+#define NR_PORTS        64
+
+#define SERIAL_PARANOIA_CHECK
+#undef  SERIAL_DEBUG_OPEN
+#undef  SERIAL_DEBUG_THROTTLE
+#undef  SERIAL_DEBUG_OTHER
+#undef  SERIAL_DEBUG_IO
+#undef  SERIAL_DEBUG_COUNT
+#undef  SERIAL_DEBUG_DTR
+#undef  CYCLOM_16Y_HACK
+#undef  CYCLOM_ENABLE_MONITORING
+#undef  CY_PCI_DEBUG
+
+
+#if 0
+#define PAUSE __asm__("nop");
+#else
+#define PAUSE ;
+#endif
+
+#define cy_min(a,b) (((a)<(b))?(a):(b))
+
+#define CHARS_IN_BUF(buf_ctrl) \
+    ((buf_ctrl->rx_put - \
+      buf_ctrl->rx_get + \
+      buf_ctrl->rx_bufsize) % \
+		  buf_ctrl->rx_bufsize)
+
+#define SPACE_IN_BUF(buf_ctrl) \
+    ((buf_ctrl->tx_get - \
+      buf_ctrl->tx_put + \
+      buf_ctrl->tx_bufsize - 1) % \
+		  buf_ctrl->tx_bufsize)
+
+
 #include <linux/module.h>
 
 #include <linux/errno.h>
@@ -280,7 +445,7 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>
+#include <asm/segment.h>
 #include <asm/bitops.h>
 
 #include <linux/config.h>
@@ -290,24 +455,34 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 
-#define small_delay(x) for(j=0;j<x;j++)k++;
+#include <linux/version.h>
 
+#if LINUX_VERSION_CODE >= 131328
 
-#define SERIAL_PARANOIA_CHECK
-#undef  SERIAL_DEBUG_OPEN
-#undef  SERIAL_DEBUG_THROTTLE
-#undef  SERIAL_DEBUG_OTHER
-#undef  SERIAL_DEBUG_IO
-#undef  SERIAL_DEBUG_COUNT
-#undef  SERIAL_DEBUG_DTR
-#undef  CYCLOM_16Y_HACK
-#undef  CYCLOM_ENABLE_MONITORING
+#include <asm/uaccess.h>
+
+#define memcpy_fromfs	copy_from_user
+#define memcpy_tofs	copy_to_user
+#define put_fs_long	put_user
+#define vremap		ioremap
+
+static unsigned long get_fs_long(unsigned long *addr)
+{
+	unsigned long result = 0;
+	int error = get_user (result, addr);
+	if (error)
+		printk ("cyclades: get_fs_long: error == %d\n", error);
+	return result;
+}
+
+#endif
 
 #ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
 #endif
+#define IS_CYC_Z(card) ((card).num_chips == 1)
 
-#define WAKEUP_CHARS 256
+#define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256)
 
 #define STD_COM_FLAGS (0)
 
@@ -325,72 +500,39 @@
 static unsigned char *intr_base_addr;
 
 
-/* This is the address lockup table. The driver will probe for Cyclom-Y/ISA
-   boards at all addresses in here. If you want the driver to probe addresses
-   in a different address, add it to this table.
-   If the driver is probing some other board and causing problems, remove the
-   address from this table.  */
+/* This is the address lookup table. The driver will probe for
+   Cyclom-Y/ISA boards at all addresses in here. If you want the
+   driver to probe addresses at a different address, add it to
+   this table.  If the driver is probing some other board and
+   causing problems, remove the offending address from this table.
+   The cy_setup function extracts additional addresses from the
+   boot options line.  The form is "cyclades=address,address..."
+*/
 
 static unsigned char *cy_isa_addresses[] = {
-	(unsigned char *) 0xD0000,
-	(unsigned char *) 0xD2000,
-	(unsigned char *) 0xD4000,
-	(unsigned char *) 0xD6000,
-	(unsigned char *) 0xD8000,
-	(unsigned char *) 0xDA000,
-	(unsigned char *) 0xDC000,
-	(unsigned char *) 0xDE000,
+        (unsigned char *) 0xD0000,
+        (unsigned char *) 0xD2000,
+        (unsigned char *) 0xD4000,
+        (unsigned char *) 0xD6000,
+        (unsigned char *) 0xD8000,
+        (unsigned char *) 0xDA000,
+        (unsigned char *) 0xDC000,
+        (unsigned char *) 0xDE000,
+        0,0,0,0,0,0,0,0
 };
-#define	NR_ISA_ADDRESSES	(sizeof(cy_isa_addresses)/sizeof(unsigned char *))
+#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
 /* This is the per-card data structure containing address, irq, number of
-   channels, etc. This driver supports a maximum of NR_CARDS cards. If
-   you need to install more boards, change this constant in the definition
-   below. No other change is necessary to support more boards. */
-
-#define NR_CARDS	4
-
+   channels, etc. This driver supports a maximum of NR_CARDS cards.
+*/
 static struct cyclades_card cy_card[NR_CARDS];
 
 /* This is the per-channel data structure containing pointers, flags
-   and variables for the port. This driver supports a maximum of NR_PORTS.
-   If the total number of ports is larger than NR_PORTS, change this
-   constant in the definition below. No other change is necessary to
-   support more boards/ports. */
-
-#define NR_PORTS        64
-
+ and variables for the port. This driver supports a maximum of NR_PORTS.
+*/
 static struct cyclades_port cy_port[NR_PORTS];
 
-/*  The Cyclom-Ye has placed the sequential chips in non-sequential
- *  address order.  This look-up table overcomes that problem.
- */
-static int cy_chip_offset [] =
-    { 0x0000,
-      0x0400,
-      0x0800,
-      0x0C00,
-      0x0200,
-      0x0600,
-      0x0A00,
-      0x0E00
-    };
-
-/* PCI related definitions */
-
-static unsigned short	cy_pci_nboard = 0;
-static unsigned short	cy_isa_nboard = 0;
-static unsigned short	cy_nboard = 0;
-static unsigned short	cy_pci_dev_id[] = {
-				PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
-				PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
-				0			/* end of table */
-			};
-
-int			cy_detect_isa(void);
-int			cy_detect_pci(void);
-
-static int		cy_next_channel = 0;	/* next minor available */
+static int cy_next_channel = 0; /* next minor available */
 
 static int serial_refcount;
 
@@ -401,17 +543,18 @@
 /* This is the per-irq data structure,
    it maps an irq to the corresponding card */
 
-struct cyclades_card	*IRQ_cards[16];
+static struct cyclades_card     *IRQ_cards[16];
 
 
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
  * and some other program tries to do a serial write at the same time.
  * Since the lock will only come under contention when the system is
  * swapping and available memory is low, it makes sense to share one
  * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
+ * memory if large numbers of serial ports are open.  This buffer is
+ * allocated when the first cy_open occurs.
  */
 static unsigned char *tmp_buf = 0;
 static struct semaphore tmp_buf_sem = MUTEX;
@@ -420,83 +563,127 @@
  * This is used to look up the divisor speeds and the timeouts
  * We're normally limited to 15 distinct baud rates.  The extra
  * are accessed via settings in info->flags.
- *         0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
- *        10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
- *                                                  HI            VHI
+ *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+ *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
+ *                                               HI            VHI
  */
 static int baud_table[] = {
-           0,    50,    75,   110,   134,   150,   200,   300,   600,  1200,
-        1800,  2400,  4800,  9600, 19200, 38400, 57600, 76800,115200,150000,
-        0};
+       0,    50,    75,   110,   134,   150,   200,   300,   600,  1200,
+    1800,  2400,  4800,  9600, 19200, 38400, 57600, 76800,115200,150000,
+    0};
 
 static char baud_co[] = {  /* 25 MHz clock option table */
-        /* value =>    00    01   02    03    04 */
-        /* divide by    8    32   128   512  2048 */
-        0x00,  0x04,  0x04,  0x04,  0x04,  0x04,  0x03,  0x03,  0x03,  0x02,
-        0x02,  0x02,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00};
+    /* value =>    00    01   02    03    04 */
+    /* divide by    8    32   128   512  2048 */
+    0x00,  0x04,  0x04,  0x04,  0x04,  0x04,  0x03,  0x03,  0x03,  0x02,
+    0x02,  0x02,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00};
 
 static char baud_bpr[] = {  /* 25 MHz baud rate period table */
-        0x00,  0xf5,  0xa3,  0x6f,  0x5c,  0x51,  0xf5,  0xa3,  0x51,  0xa3,
-        0x6d,  0x51,  0xa3,  0x51,  0xa3,  0x51,  0x36,  0x29,  0x1b,  0x15};
+    0x00,  0xf5,  0xa3,  0x6f,  0x5c,  0x51,  0xf5,  0xa3,  0x51,  0xa3,
+    0x6d,  0x51,  0xa3,  0x51,  0xa3,  0x51,  0x36,  0x29,  0x1b,  0x15};
 
 static char baud_cor3[] = {  /* receive threshold */
-        0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,
-        0x0a,  0x0a,  0x0a,  0x09,  0x09,  0x08,  0x08,  0x08,  0x08,  0x07};
+    0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,
+    0x0a,  0x0a,  0x0a,  0x09,  0x09,  0x08,  0x08,  0x08,  0x08,  0x07};
 
 
+/*  The Cyclom-Ye has placed the sequential chips in non-sequential
+ *  address order.  This look-up table overcomes that problem.
+ */
+static int cy_chip_offset [] =
+    { 0x0000,
+      0x0400,
+      0x0800,
+      0x0C00,
+      0x0200,
+      0x0600,
+      0x0A00,
+      0x0E00
+    };
+
+/* PCI related definitions */
 
-static void shutdown(struct cyclades_port *);
-static int startup (struct cyclades_port *);
-static void cy_throttle(struct tty_struct *);
-static void cy_unthrottle(struct tty_struct *);
-static void config_setup(struct cyclades_port *);
+static unsigned short   cy_pci_nboard = 0;
+static unsigned short   cy_isa_nboard = 0;
+static unsigned short   cy_nboard = 0;
+static unsigned short   cy_pci_dev_id[] = {
+			    PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
+			    PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
+			    PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */
+			    PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */
+			    0                       /* end of table */
+                        };
+
+
+static void cy_start(struct tty_struct *);
+static void set_line_char(struct cyclades_port *);
+static void cy_probe(int, void *, struct pt_regs *);
+static void cyz_poll(unsigned long);
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
 #endif
 
 
+static int cyz_timeron = 0;
+static struct timer_list
+cyz_timerlist = {
+    NULL, NULL, 0, 0, cyz_poll
+};
+
+
+/**************************************************
+error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+memcpy_tofs  (to, from, count);
+***************************************************************
+error = verify_area(VERIFY_READ,  (void *) arg, sizeof(unsigned long *));
+memcpy_fromfs(to, from, count);
+**************************************************/
+
+
 static inline int
 serial_paranoia_check(struct cyclades_port *info,
-			kdev_t device, const char *routine)
+                        kdev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
     static const char *badmagic =
-	"Warning: bad magic number for serial struct (%s) in %s\n";
+        "cyc Warning: bad magic number for serial struct (%s) in %s\n";
     static const char *badinfo =
-	"Warning: null cyclades_port for (%s) in %s\n";
+        "cyc Warning: null cyclades_port for (%s) in %s\n";
     static const char *badrange =
-	"Warning: cyclades_port out of range for (%s) in %s\n";
+        "cyc Warning: cyclades_port out of range for (%s) in %s\n";
 
     if (!info) {
-	printk(badinfo, kdevname(device), routine);
-	return 1;
+        printk(badinfo, kdevname(device), routine);
+        return 1;
     }
 
     if( (long)info < (long)(&cy_port[0])
     || (long)(&cy_port[NR_PORTS]) < (long)info ){
-	printk(badrange, kdevname(device), routine);
-	return 1;
+        printk(badrange, kdevname(device), routine);
+        return 1;
     }
 
     if (info->magic != CYCLADES_MAGIC) {
-	printk(badmagic, kdevname(device), routine);
-	return 1;
+        printk(badmagic, kdevname(device), routine);
+        return 1;
     }
 #endif
-	return 0;
+        return 0;
 } /* serial_paranoia_check */
 
+
 /* The following diagnostic routines allow the driver to spew
    information on the screen, even (especially!) during interrupts.
  */
-void
+static void
 SP(char *data){
   unsigned long flags;
     save_flags(flags); cli();
         console_print(data);
     restore_flags(flags);
-}
-void
+}/* SP */
+
+static void
 CP(char data){
   unsigned long flags;
   char scrn[2];
@@ -507,161 +694,312 @@
     restore_flags(flags);
 }/* CP */
 
-void CP1(int data) { (data<10)?  CP(data+'0'): CP(data+'A'-10); }/* CP1 */
-void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
-void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
-void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
+static void CP4(int data)
+    { (data<10)?  CP(data+'0'): CP(data+'A'-10); }/* CP4 */
+static void CP8(int data)
+    { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
+static void CP16(int data)
+    { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
+static void CP32(long data)
+    { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
 
-/* This routine waits up to 1000 micro-seconds for the previous
-   command to the Cirrus chip to complete and then issues the
-   new command.  An error is returned if the previous command
-   didn't finish within the time limit.
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver
+ * (also known as the "bottom half").  This can be called any
+ * number of times for any channel without harm.
  */
-u_short
-write_cy_cmd(u_char *base_addr, u_char cmd, int index)
+static inline void
+cy_sched_event(struct cyclades_port *info, int event)
 {
-  unsigned long flags;
-  volatile int  i;
-
-    save_flags(flags); cli();
-	/* Check to see that the previous command has completed */
-	for(i = 0 ; i < 100 ; i++){
-	    if (base_addr[CyCCR<<index] == 0){
-		break;
-	    }
-	    udelay(10L);
-	}
-	/* if the CCR never cleared, the previous command
-	    didn't finish within the "reasonable time" */
-	if ( i == 100 ) {
-	    restore_flags(flags);
-	    return (-1);
-	}
+    info->event |= 1 << event; /* remember what kind of event and who */
+    queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
+    mark_bh(CYCLADES_BH);                       /* then trigger event */
+} /* cy_sched_event */
 
-	/* Issue the new command */
-	base_addr[CyCCR<<index] = cmd;
-    restore_flags(flags);
-    return(0);
-} /* write_cy_cmd */
 
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using cy_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the tq_cyclades work queue and sets a request flag
+ * via mark_bh for processing that queue.  When the time is right,
+ * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the cyclades_port
+ * structure) to the bottom half of the driver.  Previous kernels
+ * had to poll every port to see if that port needed servicing.
+ */
+static void
+do_cyclades_bh(void)
+{
+    run_task_queue(&tq_cyclades);
+} /* do_cyclades_bh */
 
-/* cy_start and cy_stop provide software output flow control as a
-   function of XON/XOFF, software CTS, and other such stuff. */
 
 static void
-cy_stop(struct tty_struct *tty)
+do_softint(void *private_)
 {
-  struct cyclades_card *cinfo;
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned char *base_addr;
-  int chip,channel,index;
-  unsigned long flags;
+  struct cyclades_port *info = (struct cyclades_port *) private_;
+  struct tty_struct    *tty;
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_stop ttyC%d\n", info->line); /* */
-#endif
+    tty = info->tty;
+    if (!tty)
+        return;
 
-    if (serial_paranoia_check(info, tty->device, "cy_stop"))
-	return;
-	
-    cinfo = &cy_card[info->card];
-    index = cinfo->bus_index;
-    channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    base_addr = (unsigned char*)
-                   (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+    if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+        tty_hangup(info->tty);
+        wake_up_interruptible(&info->open_wait);
+        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+                             ASYNC_CALLOUT_ACTIVE);
+    }
+    if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->open_wait);
+    }
+    if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+        if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
+        && tty->ldisc.write_wakeup){
+            (tty->ldisc.write_wakeup)(tty);
+        }
+        wake_up_interruptible(&tty->write_wait);
+    }
+} /* do_softint */
 
-    save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)(channel & 0x0003); /* index channel */
-        base_addr[CySRER<<index] &= ~CyTxMpty;
-    restore_flags(flags);
 
-    return;
-} /* cy_stop */
+/***********************************************************/
+/********* Start of block of Cyclom-Y specific code ********/
 
-static void
-cy_start(struct tty_struct *tty)
+/* This routine waits up to 1000 micro-seconds for the previous
+   command to the Cirrus chip to complete and then issues the
+   new command.  An error is returned if the previous command
+   didn't finish within the time limit.
+ */
+static int
+cyy_issue_cmd(u_char *base_addr, u_char cmd, int index)
 {
-  struct cyclades_card *cinfo;
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned char *base_addr;
-  int chip,channel,index;
   unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_start ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_start"))
-	return;
-	
-    cinfo = &cy_card[info->card];
-    index = cinfo->bus_index;
-    channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    base_addr = (unsigned char*)
-                   (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
+  volatile int  i;
 
     save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
-        base_addr[CySRER<<index] |= CyTxMpty;
-    restore_flags(flags);
+        /* Check to see that the previous command has completed */
+        for(i = 0 ; i < 100 ; i++){
+            if (base_addr[CyCCR<<index] == 0){
+                break;
+            }
+            udelay(10L);
+        }
+        /* if the CCR never cleared, the previous command
+            didn't finish within the "reasonable time" */
+        if ( i == 100 ) {
+            restore_flags(flags);
+            return (-1);
+        }
 
-    return;
-} /* cy_start */
+        /* Issue the new command */
+        base_addr[CyCCR<<index] = cmd;
+    restore_flags(flags);
+    return(0);
+} /* cyy_issue_cmd */
 
+static int probe_ready;
 
 /*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half").  This can be called any
- * number of times for any channel without harm.
+ * Grab all interrupts in preparation for doing an automatic irq
+ * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
+ * mask of irq's which were grabbed and should therefore be freed
+ * using free_all_interrupts().
  */
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static int
+grab_all_interrupts(int dontgrab)
 {
-    info->event |= 1 << event; /* remember what kind of event and who */
-    queue_task_irq_off(&info->tqueue, &tq_cyclades); /* it belongs to */
-    mark_bh(CYCLADES_BH);                       /* then trigger event */
-} /* cy_sched_event */
-
-
-static int probe_ready;
+  int irq_lines = 0;
+  int i, mask;
+    
+    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+        if (!(mask & dontgrab)
+        && !request_irq(i, cy_probe,
+	             SA_INTERRUPT, "serial probe", NULL)) {
+            irq_lines |= mask;
+        }
+    }
+    return irq_lines;
+} /* grab_all_interrupts */
 
 /*
- * This interrupt routine is used
- * while we are probing for submarines.
+ * Release all interrupts grabbed by grab_all_interrupts
  */
 static void
-cy_probe(int irq, void *dev_id, struct pt_regs *regs)
+free_all_interrupts(int irq_lines)
 {
-  int save_xir, save_car;
-  int index = 0;	/* probing interrupts is only for ISA */
-
-    if (!probe_ready) {
-	*(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
-        return;
+  int i;
+    
+    for (i = 0; i < 16; i++) {
+        if (irq_lines & (1 << i))
+            free_irq(i,NULL);
     }
+} /* free_all_interrupts */
 
-    cy_irq_triggered = irq;
-    cy_triggered |= 1 << irq;
-
-	if(intr_base_addr[CySVRR<<index] != 0) {
-	    save_xir = (u_char) intr_base_addr[CyTIR<<index];
-	    save_car = intr_base_addr[CyCAR<<index];
-	    if ((save_xir & 0x3) != 0){
-		SP("channel ");
-		CP2(save_xir);
-		SP(" requesting unexpected interrupt\n");
-	    }
-	    intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
-	    intr_base_addr[CySRER<<index] &= ~CyTxMpty;
-	    intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
-	    intr_base_addr[CyCAR<<index] = (save_car);
-	}
-	*(intr_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+/*
+ * This routine returns a bitfield of "wild interrupts".  Basically,
+ * any unclaimed interrupts which is flapping around.
+ */
+static int
+check_wild_interrupts(void)
+{
+  int   i, mask;
+  int   wild_interrupts = 0;
+  int   irq_lines;
+  unsigned long timeout;
+  unsigned long flags;
+        
+    /*Turn on interrupts (they may be off) */
+    save_flags(flags); sti();
+
+        irq_lines = grab_all_interrupts(0);
+       
+        /*
+         * Delay for 0.1 seconds -- we use a busy loop since this may 
+         * occur during the bootup sequence
+         */
+        timeout = jiffies+10;
+        while (timeout >= jiffies)
+            ;
+        
+        cy_triggered = 0;       /* Reset after letting things settle */
+
+        timeout = jiffies+10;
+        while (timeout >= jiffies)
+                ;
+        
+        for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+            if ((cy_triggered & (1 << i)) &&
+                (irq_lines & (1 << i))) {
+                    wild_interrupts |= mask;
+            }
+        }
+        free_all_interrupts(irq_lines);
+    restore_flags(flags);
+    return wild_interrupts;
+} /* check_wild_interrupts */
+
+/*
+ * This routine is called by do_auto_irq(); it attempts to determine
+ * which interrupt a serial port is configured to use.  It is not
+ * fool-proof, but it works a large part of the time.
+ */
+static int
+get_auto_irq(unsigned char *address)
+{
+  unsigned long timeout;
+  unsigned char *base_addr;
+  int           index;
+
+    index = 0;  /* IRQ probing is only for ISA */
+    base_addr = address;
+    intr_base_addr = address;
+        
+    /*
+     * Enable interrupts and see who answers
+     */
+    cy_irq_triggered = 0;
+    cli();
+        base_addr[CyCAR<<index] = 0;
+        cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
+        base_addr[CySRER<<index] |= CyTxMpty;
+        probe_ready = 1;
+    sti();
+    
+    timeout = jiffies+2;
+    while (timeout >= jiffies) {
+        if (cy_irq_triggered)
+            break;
+    }
+    probe_ready = 0;
+    return(cy_irq_triggered);
+} /* get_auto_irq */
+
+/*
+ * Calls get_auto_irq() multiple times, to make sure we don't get
+ * faked out by random interrupts
+ */
+static int
+do_auto_irq(unsigned char *address)
+{
+  int                   irq_lines = 0;
+  int                   irq_try_1 = 0, irq_try_2 = 0;
+  int                   retries;
+  unsigned long flags;
+
+    /* Turn on interrupts (they may be off) */
+    save_flags(flags); sti();
+
+        probe_ready = 0;
+
+        cy_wild_int_mask = check_wild_interrupts();
+
+        irq_lines = grab_all_interrupts(cy_wild_int_mask);
+        
+        for (retries = 0; retries < 5; retries++) {
+            if (!irq_try_1)
+                irq_try_1 = get_auto_irq(address);
+            if (!irq_try_2)
+                irq_try_2 = get_auto_irq(address);
+            if (irq_try_1 && irq_try_2) {
+                if (irq_try_1 == irq_try_2)
+                    break;
+                irq_try_1 = irq_try_2 = 0;
+            }
+        }
+    restore_flags(flags);
+    free_all_interrupts(irq_lines);
+    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+} /* do_auto_irq */
+
+
+/*
+ * This interrupt routine is used
+ * while we are probing for submarines.
+ */
+static void
+cy_probe(int irq, void *dev_id, struct pt_regs *regs)
+{
+  int save_xir, save_car;
+  int index = 0;        /* probing interrupts is only for ISA */
+
+    if (!probe_ready) {
+        *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+        return;
+    }
+
+    cy_irq_triggered = irq;
+    cy_triggered |= 1 << irq;
+
+        if(intr_base_addr[CySVRR<<index] != 0) {
+            save_xir = (u_char) intr_base_addr[CyTIR<<index];
+            save_car = intr_base_addr[CyCAR<<index];
+            if ((save_xir & 0x3) != 0){
+                SP("channel ");
+                CP8(save_xir);
+                SP(" requesting unexpected interrupt\n");
+            }
+            intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
+            intr_base_addr[CySRER<<index] &= ~CyTxMpty;
+            intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
+            intr_base_addr[CyCAR<<index] = (save_car);
+        }
+        *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+	                          /* Cy_ClrIntr is 0x1800 */
     return;
 } /* cy_probe */
 
@@ -670,7 +1008,7 @@
    received, out buffer empty, modem change, etc.
  */
 static void
-cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
   struct tty_struct *tty;
   int status;
@@ -703,8 +1041,8 @@
     do{
         had_work = 0;
         for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
-	    base_addr = (unsigned char *)
-	                   (cinfo->base_addr + (cy_chip_offset[chip]<<index));
+            base_addr = (unsigned char *)
+		       (cinfo->base_addr + (cy_chip_offset[chip]<<index));
             too_many = 0;
             while ( (status = base_addr[CySVRR<<index]) != 0x00) {
                 had_work++;
@@ -712,12 +1050,12 @@
                    no chip can monopolize the driver.  This forces the
                    chips to be checked in a round-robin fashion (after
                    draining each of a bunch (1000) of characters).
-		 */
+                 */
                 if(1000<too_many++){
                     break;
                 }
-                if (status & CySRReceive) {      /* reception interrupt */
-                    /* determine the channel and change to that context */
+                if (status & CySRReceive) { /* reception interrupt */
+                    /* determine the channel & change to that context */
                     save_xir = (u_char) base_addr[CyRIR<<index];
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
@@ -746,82 +1084,84 @@
                                 continue;
                             }
                             if (tty->flip.count < TTY_FLIPBUF_SIZE){
-				tty->flip.count++;
-				if (data & info->read_status_mask){
-				    if(data & CyBREAK){
-					*tty->flip.flag_buf_ptr++ =
-								TTY_BREAK;
-					*tty->flip.char_buf_ptr++ =
-							base_addr[CyRDSR<<index];
-					if (info->flags & ASYNC_SAK){
-					    do_SAK(tty);
-					}
-				    }else if(data & CyFRAME){
-					*tty->flip.flag_buf_ptr++ =
-								TTY_FRAME;
-					*tty->flip.char_buf_ptr++ =
-							base_addr[CyRDSR<<index];
-				    }else if(data & CyPARITY){
-					*tty->flip.flag_buf_ptr++ =
-								TTY_PARITY;
-					*tty->flip.char_buf_ptr++ =
-							base_addr[CyRDSR<<index];
-				    }else if(data & CyOVERRUN){
-					*tty->flip.flag_buf_ptr++ =
-								TTY_OVERRUN;
-					*tty->flip.char_buf_ptr++ = 0;
-					/* If the flip buffer itself is
-					   overflowing, we still loose
-					   the next incoming character.
-					 */
-					if(tty->flip.count < TTY_FLIPBUF_SIZE){
-					    tty->flip.count++;
-					    *tty->flip.flag_buf_ptr++ =
-					                         TTY_NORMAL;
-					    *tty->flip.char_buf_ptr++ =
-							base_addr[CyRDSR<<index];
-					}
-				    /* These two conditions may imply */
-				    /* a normal read should be done. */
-				    /* }else if(data & CyTIMEOUT){ */
-				    /* }else if(data & CySPECHAR){ */
-				    }else{
-					*tty->flip.flag_buf_ptr++ = 0;
-					*tty->flip.char_buf_ptr++ = 0;
-				    }
-				}else{
-				    *tty->flip.flag_buf_ptr++ = 0;
-				    *tty->flip.char_buf_ptr++ = 0;
-				}
+                                tty->flip.count++;
+                                if (data & info->read_status_mask){
+                                    if(data & CyBREAK){
+                                        *tty->flip.flag_buf_ptr++ =
+							    TTY_BREAK;
+                                        *tty->flip.char_buf_ptr++ =
+						base_addr[CyRDSR<<index];
+                                        if (info->flags & ASYNC_SAK){
+                                            do_SAK(tty);
+                                        }
+                                    }else if(data & CyFRAME){
+                                        *tty->flip.flag_buf_ptr++ =
+							    TTY_FRAME;
+                                        *tty->flip.char_buf_ptr++ =
+						base_addr[CyRDSR<<index];
+                                    }else if(data & CyPARITY){
+                                        *tty->flip.flag_buf_ptr++ =
+							    TTY_PARITY;
+                                        *tty->flip.char_buf_ptr++ =
+						base_addr[CyRDSR<<index];
+                                    }else if(data & CyOVERRUN){
+                                        *tty->flip.flag_buf_ptr++ =
+							    TTY_OVERRUN;
+                                        *tty->flip.char_buf_ptr++ = 0;
+                                        /* If the flip buffer itself is
+                                           overflowing, we still loose
+                                           the next incoming character.
+                                         */
+                                        if(tty->flip.count
+					           < TTY_FLIPBUF_SIZE){
+                                            tty->flip.count++;
+                                            *tty->flip.flag_buf_ptr++ =
+							     TTY_NORMAL;
+                                            *tty->flip.char_buf_ptr++ =
+						base_addr[CyRDSR<<index];
+                                        }
+                                    /* These two conditions may imply */
+                                    /* a normal read should be done. */
+                                    /* }else if(data & CyTIMEOUT){ */
+                                    /* }else if(data & CySPECHAR){ */
+                                    }else{
+                                        *tty->flip.flag_buf_ptr++ = 0;
+                                        *tty->flip.char_buf_ptr++ = 0;
+                                    }
+                                }else{
+                                    *tty->flip.flag_buf_ptr++ = 0;
+                                    *tty->flip.char_buf_ptr++ = 0;
+                                }
                             }else{
-                                /* there was a software buffer overrun
-				    and nothing could be done about it!!! */
+                                /* there was a software buffer
+				   overrun and nothing could be
+				   done about it!!! */
                             }
                         } else { /* normal character reception */
-                            /* load # characters available from the chip */
+                            /* load # chars available from the chip */
                             char_count = base_addr[CyRDCR<<index];
 
 #ifdef CYCLOM_ENABLE_MONITORING
-			    ++info->mon.int_count;
-			    info->mon.char_count += char_count;
-			    if (char_count > info->mon.char_max)
-			       info->mon.char_max = char_count;
-			    info->mon.char_last = char_count;
+                            ++info->mon.int_count;
+                            info->mon.char_count += char_count;
+                            if (char_count > info->mon.char_max)
+                               info->mon.char_max = char_count;
+                            info->mon.char_last = char_count;
 #endif
                             while(char_count--){
-				if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+                                if (tty->flip.count >= TTY_FLIPBUF_SIZE){
                                         break;
                                 }
-				tty->flip.count++;
+                                tty->flip.count++;
                                 data = base_addr[CyRDSR<<index];
-				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-				*tty->flip.char_buf_ptr++ = data;
+                                *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+                                *tty->flip.char_buf_ptr++ = data;
 #ifdef CYCLOM_16Y_HACK
-				udelay(10L);
+                                udelay(10L);
 #endif
                             }
                         }
-                        queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+                        queue_task(&tty->flip.tqueue, &tq_timer);
                     }
                     /* end of service */
                     base_addr[CyRIR<<index] = (save_xir & 0x3f);
@@ -829,18 +1169,19 @@
                 }
 
 
-                if (status & CySRTransmit) {     /* transmission interrupt */
-                    /* Since we only get here when the transmit buffer is empty,
-                        we know we can always stuff a dozen characters. */
+                if (status & CySRTransmit) { /* transmission interrupt */
+                    /* Since we only get here when the transmit buffer
+                       is empty, we know we can always stuff a dozen
+                       characters. */
 
-                    /* determine the channel and change to that context */
+                    /* determine the channel & change to that context */
                     save_xir = (u_char) base_addr[CyTIR<<index];
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
                     save_car = base_addr[CyCAR<<index];
                     base_addr[CyCAR<<index] = save_xir;
 
-                    /* validate the port number (as configured and open) */
+                    /* validate the port# (as configured and open) */
                     if( (i < 0) || (NR_PORTS <= i) ){
                         base_addr[CySRER<<index] &= ~CyTxMpty;
                         goto txend;
@@ -852,7 +1193,7 @@
                         goto txdone;
                     }
 
-                    /* load the on-chip space available for outbound data */
+                    /* load the on-chip space for outbound data */
                     char_count = info->xmit_fifo_size;
 
 
@@ -863,64 +1204,65 @@
                         info->x_char = 0;
                     }
 
-		    if (info->x_break){
-			/*  The Cirrus chip requires the "Embedded Transmit
-			    Commands" of start break, delay, and end break
-			    sequences to be sent.  The duration of the
-			    break is given in TICs, which runs at HZ
-			    (typically 100) and the PPR runs at 200 Hz,
-			    so the delay is duration * 200/HZ, and thus a
-			    break can run from 1/100 sec to about 5/4 sec.
-			 */
-			base_addr[CyTDR<<index] = 0; /* start break */
-			base_addr[CyTDR<<index] = 0x81;
-			base_addr[CyTDR<<index] = 0; /* delay a bit */
-			base_addr[CyTDR<<index] = 0x82;
-			base_addr[CyTDR<<index] = info->x_break*200/HZ;
-			base_addr[CyTDR<<index] = 0; /* terminate break */
-			base_addr[CyTDR<<index] = 0x83;
-			char_count -= 7;
-			info->x_break = 0;
-		    }
+                    if (info->x_break){
+                        /*  The Cirrus chip requires the "Embedded
+			    Transmit Commands" of start break, delay,
+			    and end break sequences to be sent.  The
+			    duration of the break is given in TICs,
+			    which runs at HZ (typically 100) and the
+			    PPR runs at 200 Hz, so the delay is
+			    duration * 200/HZ, and thus a break can
+			    run from 1/100 sec to about 5/4 sec.
+                         */
+                        base_addr[CyTDR<<index] = 0; /* start break */
+                        base_addr[CyTDR<<index] = 0x81;
+                        base_addr[CyTDR<<index] = 0; /* delay a bit */
+                        base_addr[CyTDR<<index] = 0x82;
+                        base_addr[CyTDR<<index] = info->x_break*200/HZ;
+                        base_addr[CyTDR<<index] = 0; /* finish break */
+                        base_addr[CyTDR<<index] = 0x83;
+                        char_count -= 7;
+                        info->x_break = 0;
+                    }
 
                     while (char_count-- > 0){
                         if (!info->xmit_cnt){
-			    base_addr[CySRER<<index] &= ~CyTxMpty;
-			    goto txdone;
+                            base_addr[CySRER<<index] &= ~CyTxMpty;
+                            goto txdone;
                         }
-			if (info->xmit_buf == 0){
-			    base_addr[CySRER<<index] &= ~CyTxMpty;
-			    goto txdone;
-			}
-			if (info->tty->stopped || info->tty->hw_stopped){
-			    base_addr[CySRER<<index] &= ~CyTxMpty;
-			    goto txdone;
-			}
-                        /* Because the Embedded Transmit Commands have been
-                           enabled, we must check to see if the escape
-                           character, NULL, is being sent.  If it is, we
-                           must ensure that there is room for it to be
-                           doubled in the output stream.  Therefore we
-                           no longer advance the pointer when the character
-                           is fetched, but rather wait until after the check
-                           for a NULL output character. (This is necessary
-                           because there may not be room for the two chars
-                           needed to send a NULL.
-		         */
+                        if (info->xmit_buf == 0){
+                            base_addr[CySRER<<index] &= ~CyTxMpty;
+                            goto txdone;
+                        }
+                        if (info->tty->stopped || info->tty->hw_stopped){
+                            base_addr[CySRER<<index] &= ~CyTxMpty;
+                            goto txdone;
+                        }
+                        /* Because the Embedded Transmit Commands have
+                           been enabled, we must check to see if the
+			   escape character, NULL, is being sent.  If it
+			   is, we must ensure that there is room for it
+			   to be doubled in the output stream.  Therefore
+			   we no longer advance the pointer when the
+			   character is fetched, but rather wait until
+			   after the check for a NULL output character.
+			   This is necessary because there may not be
+			   room for the two chars needed to send a NULL.)
+                         */
                         outch = info->xmit_buf[info->xmit_tail];
                         if( outch ){
-			    info->xmit_cnt--;
-			    info->xmit_tail = (info->xmit_tail + 1)
-						      & (PAGE_SIZE - 1);
-			    base_addr[CyTDR<<index] = outch;
+                            info->xmit_cnt--;
+                            info->xmit_tail = (info->xmit_tail + 1)
+                                                      & (PAGE_SIZE - 1);
+                            base_addr[CyTDR<<index] = outch;
                         }else{
                             if(char_count > 1){
-				info->xmit_cnt--;
-				info->xmit_tail = (info->xmit_tail + 1)
-							  & (PAGE_SIZE - 1);
-				base_addr[CyTDR<<index] = outch;
-				base_addr[CyTDR<<index] = 0;
-				char_count--;
+                                info->xmit_cnt--;
+                                info->xmit_tail = (info->xmit_tail + 1)
+						      & (PAGE_SIZE - 1);
+                                base_addr[CyTDR<<index] = outch;
+                                base_addr[CyTDR<<index] = 0;
+                                char_count--;
                             }else{
                             }
                         }
@@ -939,10 +1281,11 @@
 
                 if (status & CySRModem) {        /* modem interrupt */
 
-                    /* determine the channel and change to that context */
+                    /* determine the channel & change to that context */
                     save_xir = (u_char) base_addr[CyMIR<<index];
                     channel = (u_short ) (save_xir & CyIRChannel);
-                    info = &cy_port[channel + chip * 4 + cinfo->first_line];
+                    info = &cy_port[channel + chip * 4
+		                           + cinfo->first_line];
                     info->last_active = jiffies;
                     save_car = base_addr[CyCAR<<index];
                     base_addr[CyCAR<<index] = save_xir;
@@ -950,32 +1293,40 @@
                     mdm_change = base_addr[CyMISR<<index];
                     mdm_status = base_addr[CyMSVR1<<index];
 
-                    if(info->tty == 0){ /* nowhere to put the data, ignore it */
+                    if(info->tty == 0){/* no place for data, ignore it*/
                         ;
                     }else{
                         if((mdm_change & CyDCD)
                         && (info->flags & ASYNC_CHECK_CD)){
                             if(mdm_status & CyDCD){
-                                cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
-                            }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
-                                     &&(info->flags & ASYNC_CALLOUT_NOHUP))){
-                                cy_sched_event(info, Cy_EVENT_HANGUP);
+                                cy_sched_event(info,
+				    Cy_EVENT_OPEN_WAKEUP);
+                            }else if(!((info->flags
+			                & ASYNC_CALLOUT_ACTIVE)
+				 &&(info->flags
+				    & ASYNC_CALLOUT_NOHUP))){
+                                cy_sched_event(info,
+				    Cy_EVENT_HANGUP);
                             }
                         }
                         if((mdm_change & CyCTS)
                         && (info->flags & ASYNC_CTS_FLOW)){
                             if(info->tty->hw_stopped){
                                 if(mdm_status & CyCTS){
-                                    /* !!! cy_start isn't used because... */
+                                    /* cy_start isn't used
+				         because... !!! */
                                     info->tty->hw_stopped = 0;
-				    base_addr[CySRER<<index] |= CyTxMpty;
-				    cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+                                    base_addr[CySRER<<index] |= CyTxMpty;
+                                    cy_sched_event(info,
+				        Cy_EVENT_WRITE_WAKEUP);
                                 }
                             }else{
                                 if(!(mdm_status & CyCTS)){
-                                    /* !!! cy_stop isn't used because... */
+                                    /* cy_stop isn't used
+				         because ... !!! */
                                     info->tty->hw_stopped = 1;
-				    base_addr[CySRER<<index] &= ~CyTxMpty;
+                                    base_addr[CySRER<<index] &=
+				                            ~CyTxMpty;
                                 }
                             }
                         }
@@ -993,296 +1344,510 @@
     } while(had_work);
 
    /* clear interrupts */
-   *(card_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
-
-} /* cy_interrupt */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue.  When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver.  Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_cyclades_bh(void)
-{
-    run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
+   *(card_base_addr + (Cy_ClrIntr<<index)) = 0;
+                                /* Cy_ClrIntr is 0x1800 */
 
-static void
-do_softint(void *private_)
-{
-  struct cyclades_port *info = (struct cyclades_port *) private_;
-  struct tty_struct    *tty;
-
-    tty = info->tty;
-    if (!tty)
-	return;
+} /* cyy_interrupt */
 
-    if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
-	tty_hangup(info->tty);
-	wake_up_interruptible(&info->open_wait);
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|
-			     ASYNC_CALLOUT_ACTIVE);
-    }
-    if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
-	wake_up_interruptible(&info->open_wait);
-    }
-    if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-	if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-	&& tty->ldisc.write_wakeup){
-	    (tty->ldisc.write_wakeup)(tty);
-	}
-	wake_up_interruptible(&tty->write_wait);
-    }
-} /* do_softint */
+/***********************************************************/
+/********* End of block of Cyclom-Y specific code **********/
+/******** Start of block of Cyclom-Z specific code *********/
+/***********************************************************/
 
 
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
 static int
-grab_all_interrupts(int dontgrab)
+cyz_fetch_msg( struct cyclades_card *cinfo,
+	    u_long *channel, u_char *cmd, u_long **param)
 {
-  int irq_lines = 0;
-  int i, mask;
-    
-    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-	if (!(mask & dontgrab)
-	&& !request_irq(i, cy_probe, SA_INTERRUPT, "serial probe", NULL)) {
-	    irq_lines |= mask;
-	}
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  unsigned long loc_doorbell;
+
+    firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+    if (firm_id->signature != ZFIRM_ID){
+	return (-1);
+    }
+    zfw_ctrl = (struct ZFW_CTRL *)
+		    (cinfo->base_addr + firm_id->zfwctrl_addr);
+    board_ctrl = &zfw_ctrl->board_ctrl;
+
+    loc_doorbell = ((struct RUNTIME_9060 *)
+                     (cinfo->ctl_addr))->loc_doorbell;
+    if (loc_doorbell){
+	*cmd = (char)(0xff & loc_doorbell);
+	*channel = board_ctrl->fwcmd_channel;
+	*param = board_ctrl->fwcmd_param;
+	((struct RUNTIME_9060 *)
+	     (cinfo->ctl_addr))->loc_doorbell = 0xffffffff;
+	return 1;
     }
-    return irq_lines;
-} /* grab_all_interrupts */
+    return 0;
+} /* cyz_fetch_msg */
 
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
-static void
-free_all_interrupts(int irq_lines)
-{
-  int i;
-    
-    for (i = 0; i < 16; i++) {
-	if (irq_lines & (1 << i))
-	    free_irq(i,NULL);
-    }
-} /* free_all_interrupts */
 
-/*
- * This routine returns a bitfield of "wild interrupts".  Basically,
- * any unclaimed interrupts which is flapping around.
- */
 static int
-check_wild_interrupts(void)
+cyz_issue_cmd( struct cyclades_card *cinfo,
+	    u_long channel, u_char cmd, u_long *param)
 {
-  int	i, mask;
-  int	wild_interrupts = 0;
-  int	irq_lines;
-  unsigned long timeout;
-  unsigned long flags;
-	
-    /*Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
-
-	irq_lines = grab_all_interrupts(0);
-       
-	/*
-	 * Delay for 0.1 seconds -- we use a busy loop since this may 
-	 * occur during the bootup sequence
-	 */
-	timeout = jiffies+10;
-	while (timeout >= jiffies)
-	    ;
-	
-	cy_triggered = 0;	/* Reset after letting things settle */
-
-	timeout = jiffies+10;
-	while (timeout >= jiffies)
-		;
-	
-	for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-	    if ((cy_triggered & (1 << i)) &&
-		(irq_lines & (1 << i))) {
-		    wild_interrupts |= mask;
-	    }
-	}
-	free_all_interrupts(irq_lines);
-    restore_flags(flags);
-    return wild_interrupts;
-} /* check_wild_interrupts */
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  volatile unsigned long *pci_doorbell;
+  int index;
+
+    firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+    if (firm_id->signature != ZFIRM_ID){
+	return (-1);
+    }
+    zfw_ctrl = (struct ZFW_CTRL *)
+		    (cinfo->base_addr + firm_id->zfwctrl_addr);
+    board_ctrl = &zfw_ctrl->board_ctrl;
+
+    index = 0;
+    pci_doorbell = &((struct RUNTIME_9060 *)
+                     (cinfo->ctl_addr))->pci_doorbell;
+    while( (*pci_doorbell & 0xff) != 0){
+        if (index++ == 100){
+            return(-1);
+        }
+	udelay(50L);
+    }
+    board_ctrl->hcmd_channel = channel;
+    board_ctrl->hcmd_param = param;
+    *pci_doorbell = (long)cmd;
 
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use.  It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(unsigned char *address)
-{
-  unsigned long timeout;
-  unsigned char *base_addr;
-  int		index;
+    return(0);
+} /* cyz_issue_cmd */
 
-    index = 0;	/* IRQ probing is only for ISA */
-    base_addr = address;
-    intr_base_addr = address;
-	
-    /*
-     * Enable interrupts and see who answers
-     */
-    cy_irq_triggered = 0;
-    cli();
-	base_addr[CyCAR<<index] = 0;
-	write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
-	base_addr[CySRER<<index] |= CyTxMpty;
-	probe_ready = 1;
-    sti();
-    
-    timeout = jiffies+2;
-    while (timeout >= jiffies) {
-	if (cy_irq_triggered)
-	    break;
-    }
-    probe_ready = 0;
-    return(cy_irq_triggered);
-} /* get_auto_irq */
 
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
 static int
-do_auto_irq(unsigned char *address)
-{
-  int 			irq_lines = 0;
-  int			irq_try_1 = 0, irq_try_2 = 0;
-  int			retries;
-  unsigned long flags;
+cyz_update_channel( struct cyclades_card *cinfo,
+	    u_long channel, u_char mode, u_char cmd)
+{ 
+  struct FIRM_ID *firm_id =
+      (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+  struct ZFW_CTRL *zfw_ctrl;
+  struct CH_CTRL *ch_ctrl;
+
+    if (firm_id->signature != ZFIRM_ID){
+	return (-1);
+    }
+    zfw_ctrl =
+	(struct ZFW_CTRL *)(cinfo->base_addr + firm_id->zfwctrl_addr);
+    ch_ctrl = zfw_ctrl->ch_ctrl;
 
-    /* Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
+    ch_ctrl[channel].op_mode = (long)mode;
 
-	probe_ready = 0;
-
-        cy_wild_int_mask = check_wild_interrupts();
+    return cyz_issue_cmd(cinfo, channel, cmd, 0L);
 
-	irq_lines = grab_all_interrupts(cy_wild_int_mask);
-	
-	for (retries = 0; retries < 5; retries++) {
-	    if (!irq_try_1)
-		irq_try_1 = get_auto_irq(address);
-	    if (!irq_try_2)
-		irq_try_2 = get_auto_irq(address);
-	    if (irq_try_1 && irq_try_2) {
-		if (irq_try_1 == irq_try_2)
-		    break;
-		irq_try_1 = irq_try_2 = 0;
-	    }
-	}
-    restore_flags(flags);
-    free_all_interrupts(irq_lines);
-    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
+} /* cyz_update_channel */
 
 
-/* This is called whenever a port becomes active;
-   interrupts are enabled and DTR & RTS are turned on.
- */
-static int
-startup(struct cyclades_port * info)
+static void
+cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-  unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
+} /* cyz_interrupt */
 
-    if (info->flags & ASYNC_INITIALIZED){
-	return 0;
-    }
 
-    if (!info->type){
-	if (info->tty){
-	    set_bit(TTY_IO_ERROR, &info->tty->flags);
-	}
-	return 0;
-    }
-    if (!info->xmit_buf){
-	info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
-	if (!info->xmit_buf){
-	    return -ENOMEM;
+static void
+cyz_poll(unsigned long arg)
+{
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  struct CH_CTRL *ch_ctrl;
+  struct BUF_CTRL *buf_ctrl;
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info;
+  struct tty_struct *tty;
+  int card, port;
+  int char_count, small_count;
+  char data;
+  u_long channel;
+  u_char cmd;
+  u_long *param;
+
+    cyz_timerlist.expires = jiffies + 100;
+
+    for (card = 0 ; card < NR_CARDS ; card++){
+	cinfo = &cy_card[card];
+	if (!IS_CYC_Z(*cinfo)) continue;
+
+	firm_id = (struct FIRM_ID *)
+		    (cinfo->base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
+	    continue;
 	}
-    }
-
-    config_setup(info);
+
+	zfw_ctrl =
+	    (struct ZFW_CTRL *)
+	    (cinfo->base_addr + firm_id->zfwctrl_addr);
+	board_ctrl = &zfw_ctrl->board_ctrl;
+
+	while( cyz_fetch_msg( cinfo, &channel, &cmd, &param) == 1){
+	    char_count = 0;
+	    info = &cy_port[ channel + cinfo->first_line ];
+            if((tty = info->tty) == 0) continue;
+	    ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+	    buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+	    info->jiffies[0] = jiffies;
+
+	    switch(cmd){
+	    case C_CM_PR_ERROR:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+		*tty->flip.char_buf_ptr++ = 0;
+		char_count++;
+	        break;
+	    case C_CM_FR_ERROR:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+		*tty->flip.char_buf_ptr++ = 0;
+		char_count++;
+	        break;
+	    case C_CM_RXBRK:
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		*tty->flip.char_buf_ptr++ = 0;
+		char_count++;
+	        break;
+	    case C_CM_MDCD:
+		if (info->flags & ASYNC_CHECK_CD){
+		    if( ch_ctrl[channel].rs_status & C_RS_DCD){
+			/* SP("Open Wakeup\n"); */
+			cy_sched_event(info,
+			    Cy_EVENT_OPEN_WAKEUP);
+		    }else if(!((info->flags
+				& ASYNC_CALLOUT_ACTIVE)
+			 &&(info->flags
+			    & ASYNC_CALLOUT_NOHUP))){
+			/* SP("Hangup\n"); */
+			cy_sched_event(info,
+			    Cy_EVENT_HANGUP);
+		    }
+		}
+	        break;
+	    case C_CM_MCTS:
+		if (info->flags & ASYNC_CTS_FLOW) {
+		    if(info->tty->hw_stopped){
+			if( ch_ctrl[channel].rs_status & C_RS_DCD){
+			    /* cy_start isn't used because... 
+			       HW flow is handled by the board */
+			    /* SP("Write Wakeup\n"); */
+			    cy_sched_event(info,
+				Cy_EVENT_WRITE_WAKEUP);
+			}
+		    }else{
+			if(!(ch_ctrl[channel].rs_status & C_RS_CTS)){
+			    /* cy_stop isn't used because 
+			       HW flow is handled by the board */
+			    /* SP("Write stop\n"); */
+			}
+		    }
+		}
+	        break;
+	    case C_CM_MRI:
+	        break;
+	    case C_CM_MDSR:
+	        break;
+	    case C_CM_FATAL:
+		/* should do something with this !!! */
+	        break;
+	    }
+	    if(char_count){
+		queue_task(&tty->flip.tqueue, &tq_timer);
+	    }
+	}
+
+	for (port = 0; port < board_ctrl->n_channel; port++){
+	    info = &cy_port[ port + cinfo->first_line ];
+            tty = info->tty;
+	    ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+	    buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+
+	    if ((char_count = CHARS_IN_BUF(buf_ctrl))){
+		info->last_active = jiffies;
+		info->jiffies[1] = jiffies;
+
+#ifdef CYCLOM_ENABLE_MONITORING
+		info->mon.int_count++;
+		info->mon.char_count += char_count;
+		if (char_count > info->mon.char_max)
+		   info->mon.char_max = char_count;
+		info->mon.char_last = char_count;
+#endif
+		if( tty == 0){
+		    /* flush received characters */
+		    buf_ctrl->rx_get =
+		        (buf_ctrl->rx_get + char_count)
+			    % buf_ctrl->rx_bufsize;
+		    /* SP("-"); */
+		    info->rflush_count++;
+		}else{
+#ifdef BLOCKMOVE
+		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+		   for performance, but because of buffer boundaries, there
+		   may be several steps to the operation */
+		    while(0 < (small_count
+			= cy_min( (buf_ctrl->rx_bufsize - buf_ctrl->rx_get),
+			    cy_min( (TTY_FLIPBUF_SIZE - tty->flip.count),
+				char_count)))){
+			memcpy(tty->flip.char_buf_ptr,
+			       (char *)(cinfo->base_addr
+				   + buf_ctrl->rx_bufaddr
+				   + buf_ctrl->rx_get),
+			       small_count);
+			tty->flip.char_buf_ptr += small_count;
+			memset(tty->flip.flag_buf_ptr,
+			       TTY_NORMAL,
+			       small_count);
+			tty->flip.flag_buf_ptr += small_count;
+			buf_ctrl->rx_get =
+			    (buf_ctrl->rx_get + small_count)
+				% buf_ctrl->rx_bufsize;
+			char_count -= small_count;
+			tty->flip.count += small_count;
+		    }
+#else
+		    while(char_count--){
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+				break;
+			}
+			data = *(char *) (cinfo->base_addr +
+			                  buf_ctrl->rx_bufaddr +
+			                  buf_ctrl->rx_get);
+			buf_ctrl->rx_get =
+			    (buf_ctrl->rx_get + 1)
+				% buf_ctrl->rx_bufsize;
+
+			tty->flip.count++;
+			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+			*tty->flip.char_buf_ptr++ = data;
+		    }
+#endif
+		    queue_task(&tty->flip.tqueue, &tq_timer);
+		}
+	    }
+
+	    if ((char_count = SPACE_IN_BUF(buf_ctrl))){
+		if( tty == 0){
+		    goto ztxdone;
+		}
+
+		if(info->x_char) { /* send special char */
+		    data = info->x_char;
+
+		    *(char *) (cinfo->base_addr +
+		               buf_ctrl->tx_bufaddr + 
+		               buf_ctrl->tx_put) = data;
+		    buf_ctrl->tx_put =
+			(buf_ctrl->tx_put + 1)
+			    % buf_ctrl->tx_bufsize;
+		    info->x_char = 0;
+		    char_count--;
+		    info->last_active = jiffies;
+		    info->jiffies[2] = jiffies;
+		}
+		if (info->x_break){
+		    printk("cyc cyz_poll shouldn't see x_break\n");
+		    info->x_break = 0;
+		    info->last_active = jiffies;
+		    info->jiffies[2] = jiffies;
+		}
+#ifdef BLOCKMOVE
+		while(0 < (small_count
+		    = cy_min( (buf_ctrl->tx_bufsize - buf_ctrl->tx_put),
+			cy_min ( (PAGE_SIZE - info->xmit_tail),
+			  cy_min( info->xmit_cnt, char_count))))){
+		    memcpy((char *)(cinfo->base_addr
+			       + buf_ctrl->tx_bufaddr
+			       + buf_ctrl->tx_put),
+			   &info->xmit_buf[info->xmit_tail],
+			   small_count);
+		    buf_ctrl->tx_put =
+			(buf_ctrl->tx_put + small_count)
+			    % buf_ctrl->tx_bufsize;
+		    char_count -= small_count;
+		    info->xmit_cnt -= small_count;
+		    info->xmit_tail =
+			(info->xmit_tail + small_count) & (PAGE_SIZE - 1);
+		    info->last_active = jiffies;
+		    info->jiffies[2] = jiffies;
+		}
+#else
+		while (info->xmit_cnt && char_count){
+		    data = info->xmit_buf[info->xmit_tail];
+		    info->xmit_cnt--;
+		    info->xmit_tail =
+			(info->xmit_tail + 1) & (PAGE_SIZE - 1);
+
+		    *(char *) (cinfo->base_addr +
+		               buf_ctrl->tx_bufaddr +
+		               buf_ctrl->tx_put) = data;
+		    buf_ctrl->tx_put =
+		        (buf_ctrl->tx_put + 1)
+			    % buf_ctrl->tx_bufsize;
+		    char_count--;
+		    info->last_active = jiffies;
+		    info->jiffies[2] = jiffies;
+		}
+#endif
+	    ztxdone:
+		if (info->xmit_cnt < WAKEUP_CHARS) {
+		    cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+		}
+	    }
+	}
+
+	/* poll every 40 ms */
+	cyz_timerlist.expires = jiffies + 4;
+    }
+    add_timer(&cyz_timerlist);
+
+    return;
+} /* cyz_poll */
+
+
+/********** End of block of Cyclom-Z specific code *********/
+/***********************************************************/
+
+
+/* This is called whenever a port becomes active;
+   interrupts are enabled and DTR & RTS are turned on.
+ */
+static int
+startup(struct cyclades_port * info)
+{
+  unsigned long flags;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
+
+    if (info->flags & ASYNC_INITIALIZED){
+        return 0;
+    }
+
+    if (!info->type){
+        if (info->tty){
+            set_bit(TTY_IO_ERROR, &info->tty->flags);
+        }
+        return 0;
+    }
+    if (!info->xmit_buf){
+        info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
+        if (!info->xmit_buf){
+            return -ENOMEM;
+        }
+    }
+
+    set_line_char(info);
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
 		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk("startup card %d, chip %d, channel %d, base_addr %lx",
-	 card, chip, channel, (long)base_addr);/**/
+	printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
+	     card, chip, channel, (long)base_addr);/**/
 #endif
 
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = (u_char)channel;
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = (u_char)channel;
+
+	    base_addr[CyRTPR<<index] = (info->default_timeout
+				 ? info->default_timeout
+				 : 0x02); /* 10ms rx timeout */
+
+	    cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+
+	    base_addr[CyCAR<<index] =
+			 (u_char)channel; /* !!! Is this needed? */
+	    base_addr[CyMSVR1<<index] = CyRTS;
+	    base_addr[CyMSVR2<<index] = CyDTR;
 
-	base_addr[CyRTPR<<index] = (info->default_timeout
-			     ? info->default_timeout
-			     : 0x02); /* 10ms rx timeout */
+#ifdef SERIAL_DEBUG_DTR
+	    printk("cyc:startup raising DTR\n");
+	    printk("     status: 0x%x, 0x%x\n",
+		   base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+
+	    base_addr[CySRER<<index] |= CyRxData;
+	    info->flags |= ASYNC_INITIALIZED;
+
+	    if (info->tty){
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	    }
+	    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
+
+	base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+        firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
+	    return -ENODEV;
+	}
 
-	write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+	zfw_ctrl =
+	    (struct ZFW_CTRL *)
+		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
+	board_ctrl = &zfw_ctrl->board_ctrl;
+	ch_ctrl = zfw_ctrl->ch_ctrl;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+	     card, channel, (long)base_addr);/**/
+#endif
 
-	base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
-	base_addr[CyMSVR1<<index] = CyRTS;
-	base_addr[CyMSVR2<<index] = CyDTR;
+	ch_ctrl[channel].op_mode = C_CH_ENABLE;
+	ch_ctrl[channel].intr_enable = C_IN_MDCD|C_IN_MCTS;
+	retval = cyz_issue_cmd( &cy_card[card],
+	    channel, C_CM_IOCTL, 0L);	/* was C_CM_RESET */
+	if (retval != 0){
+	    printk("cyc:startup(1) retval was %x\n", retval);
+	}
 
+	/* set timeout !!! */
+	/* set RTS and DTR !!! */
+	ch_ctrl[channel].rs_control |=
+		    C_RS_RTS | C_RS_DTR ;
+	retval = cyz_issue_cmd(&cy_card[info->card],
+	    channel, C_CM_IOCTLM, 0L);
+	if (retval != 0){
+	    printk("cyc:startup(2) retval was %x\n", retval);
+	}
 #ifdef SERIAL_DEBUG_DTR
-        printk("cyc: %d: raising DTR\n", __LINE__);
-        printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+	    printk("cyc:startup raising Z DTR\n");
 #endif
 
-	base_addr[CySRER<<index] |= CyRxData;
-	info->flags |= ASYNC_INITIALIZED;
+	/* enable send, recv, modem !!! */
 
+	info->flags |= ASYNC_INITIALIZED;
 	if (info->tty){
 	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	}
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-    restore_flags(flags);
+    }
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk(" done\n");
+	printk(" cyc startup done\n");
 #endif
-    return 0;
+	return 0;
 } /* startup */
 
-void
+
+static void
 start_xmit( struct cyclades_port *info )
 {
   unsigned long flags;
@@ -1291,18 +1856,24 @@
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = channel;
-	base_addr[CySRER<<index] |= CyTxMpty;
-    restore_flags(flags);
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = channel;
+	    base_addr[CySRER<<index] |= CyTxMpty;
+	restore_flags(flags);
+    } else {
+	/* Don't have to do anything at this time */
+    }
 } /* start_xmit */
 
+
 /*
  * This routine shuts down a serial port; interrupts are disabled,
  * and DTR is dropped if the hangup on close termio flag is on.
@@ -1315,258 +1886,606 @@
   int card,chip,channel,index;
 
     if (!(info->flags & ASYNC_INITIALIZED)){
-	return;
+        return;
     }
 
     card = info->card;
     channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
+		card, chip, channel, (long)base_addr);
+#endif
+
+	/* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
+	   SENT BEFORE DROPPING THE LINE !!!  (Perhaps
+	   set some flag that is read when XMTY happens.)
+	   Other choices are to delay some fixed interval
+	   or schedule some later processing.
+	 */
+	save_flags(flags); cli();
+	    if (info->xmit_buf){
+		unsigned char * temp;
+		temp = info->xmit_buf;
+		info->xmit_buf = 0;
+		free_page((unsigned long) temp);
+	    }
+
+	    base_addr[CyCAR<<index] = (u_char)channel;
+	    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		base_addr[CyMSVR1<<index] = ~CyRTS;
+		base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc shutdown dropping DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+	    }
+	    cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
+	     /* it may be appropriate to clear _XMIT at
+	       some later date (after testing)!!! */
+
+	    if (info->tty){
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	    }
+	    info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
 
+	base_addr = (unsigned char*) (cy_card[card].base_addr);
 #ifdef SERIAL_DEBUG_OPEN
-    printk("shutdown card %d, chip %d, channel %d, base_addr %lx\n",
-	    card, chip, channel, (long)base_addr);
+    printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+		card, channel, (long)base_addr);
 #endif
 
-    /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
-       SENT BEFORE DROPPING THE LINE !!!  (Perhaps
-       set some flag that is read when XMTY happens.)
-       Other choices are to delay some fixed interval
-       or schedule some later processing.
+        firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
+	    return;
+	}
+
+	zfw_ctrl =
+	    (struct ZFW_CTRL *)
+		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
+	board_ctrl = &zfw_ctrl->board_ctrl;
+	ch_ctrl = zfw_ctrl->ch_ctrl;
+
+	save_flags(flags); cli();
+	    if (info->xmit_buf){
+		unsigned char * temp;
+		temp = info->xmit_buf;
+		info->xmit_buf = 0;
+		free_page((unsigned long) temp);
+	    }
+	    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+		ch_ctrl[channel].rs_control &=
+			    ~(C_RS_RTS | C_RS_DTR );
+		retval = cyz_issue_cmd(&cy_card[info->card],
+			channel, C_CM_IOCTLM, 0L);
+		if (retval != 0){
+		    printk("cyc:shutdown retval was %x\n",
+		        retval);
+		}
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc:shutdown dropping Z DTR\n");
+#endif
+	    }
+
+	    if (info->tty){
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	    }
+	    info->flags &= ~ASYNC_INITIALIZED;
+
+	restore_flags(flags);
+    }
+
+#ifdef SERIAL_DEBUG_OPEN
+    printk(" cyc shutdown done\n");
+#endif
+    return;
+} /* shutdown */
+
+
+/*
+ * ------------------------------------------------------------
+ * cy_open() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+                           struct cyclades_port *info)
+{
+  struct wait_queue wait = { current, NULL };
+  struct cyclades_card *cinfo;
+  unsigned long flags;
+  int chip, channel,index;
+  int retval;
+  char *base_addr;
+
+    /*
+     * If the device is in the middle of being closed, then block
+     * until it's done, and then try again.
      */
-    save_flags(flags); cli();
-	if (info->xmit_buf){
-            unsigned char * temp;
-            temp = info->xmit_buf;
-            info->xmit_buf = 0;
-	    free_page((unsigned long) temp);
+    if (info->flags & ASYNC_CLOSING) {
+        interruptible_sleep_on(&info->close_wait);
+        if (info->flags & ASYNC_HUP_NOTIFY){
+            return -EAGAIN;
+        }else{
+            return -ERESTARTSYS;
+        }
+    }
+
+    /*
+     * If this is a callout device, then just make sure the normal
+     * device isn't being used.
+     */
+    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+        if (info->flags & ASYNC_NORMAL_ACTIVE){
+            return -EBUSY;
+        }
+        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+            (info->flags & ASYNC_SESSION_LOCKOUT) &&
+            (info->session != current->session)){
+            return -EBUSY;
+        }
+        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+            (info->flags & ASYNC_PGRP_LOCKOUT) &&
+            (info->pgrp != current->pgrp)){
+            return -EBUSY;
+        }
+        info->flags |= ASYNC_CALLOUT_ACTIVE;
+        return 0;
+    }
+
+    /*
+     * If non-blocking mode is set, then make the check up front
+     * and then exit.
+     */
+    if (filp->f_flags & O_NONBLOCK) {
+        if (info->flags & ASYNC_CALLOUT_ACTIVE){
+            return -EBUSY;
+        }
+        info->flags |= ASYNC_NORMAL_ACTIVE;
+        return 0;
+    }
+
+    /*
+     * Block waiting for the carrier detect and the line to become
+     * free (i.e., not in use by the callout).  While we are in
+     * this loop, info->count is dropped by one, so that
+     * cy_close() knows when to free things.  We restore it upon
+     * exit, either normal or abnormal.
+     */
+    retval = 0;
+    add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+           info->line, info->count);/**/
+#endif
+    info->count--;
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+        current->pid, info->count);
+#endif
+    info->blocked_open++;
+
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+    if (!IS_CYC_Z(*cinfo)) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cinfo->bus_index;
+	base_addr = (char *)(cinfo->base_addr
+			    + (cy_chip_offset[chip]<<index));
+
+	while (1) {
+	    save_flags(flags); cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+		    base_addr[CyCAR<<index] = (u_char)channel;
+		    base_addr[CyMSVR1<<index] = CyRTS;
+		    base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		    printk("cyc:block_til_ready raising DTR\n");
+		    printk("     status: 0x%x, 0x%x\n",
+			base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+		}
+	    restore_flags(flags);
+	    current->state = TASK_INTERRUPTIBLE;
+	    if (tty_hung_up_p(filp)
+	    || !(info->flags & ASYNC_INITIALIZED) ){
+		if (info->flags & ASYNC_HUP_NOTIFY) {
+		    retval = -EAGAIN;
+		}else{
+		    retval = -ERESTARTSYS;
+		}
+		break;
+	    }
+	    save_flags(flags); cli();
+		base_addr[CyCAR<<index] = (u_char)channel;
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+		&& !(info->flags & ASYNC_CLOSING)
+		&& (C_CLOCAL(tty)
+		    || (base_addr[CyMSVR1<<index] & CyDCD))) {
+			restore_flags(flags);
+			break;
+		}
+	    restore_flags(flags);
+	    if (current->signal & ~current->blocked) {
+		retval = -ERESTARTSYS;
+		break;
+	    }
+#ifdef SERIAL_DEBUG_OPEN
+	    printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+		   info->line, info->count);/**/
+#endif
+	    schedule();
+	}
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
+
+	base_addr = (char *)(cinfo->base_addr);
+	firm_id = (struct FIRM_ID *)
+			(base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
+	    return -EINVAL;
 	}
 
-	base_addr[CyCAR<<index] = (u_char)channel;
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
-	    base_addr[CyMSVR1<<index] = ~CyRTS;
-	    base_addr[CyMSVR2<<index] = ~CyDTR;
+	zfw_ctrl =
+	    (struct ZFW_CTRL *)
+		(base_addr + firm_id->zfwctrl_addr);
+	board_ctrl = &zfw_ctrl->board_ctrl;
+	ch_ctrl = zfw_ctrl->ch_ctrl;
+
+	while (1) {
+	    ch_ctrl[channel].rs_control |=
+			C_RS_RTS | C_RS_DTR ;
+	    retval = cyz_issue_cmd(&cy_card[info->card],
+		    channel, C_CM_IOCTLM, 0L);
+	    if (retval != 0){
+		printk("cyc:block_til_ready retval was %x\n", retval);
+	    }
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+		    printk("cyc:block_til_ready raising Z DTR\n");
+#endif
+
+	    current->state = TASK_INTERRUPTIBLE;
+	    if (tty_hung_up_p(filp)
+	    || !(info->flags & ASYNC_INITIALIZED) ){
+		if (info->flags & ASYNC_HUP_NOTIFY) {
+		    retval = -EAGAIN;
+		}else{
+		    retval = -ERESTARTSYS;
+		}
+		break;
+	    }
+	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+	    && !(info->flags & ASYNC_CLOSING)
+	    && (C_CLOCAL(tty)
+	      || (ch_ctrl[channel].rs_status & C_RS_DCD))) {
+		break;
+	    }
+	    if (current->signal & ~current->blocked) {
+		retval = -ERESTARTSYS;
+		break;
+	    }
+#ifdef SERIAL_DEBUG_OPEN
+	    printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+		   info->line, info->count);/**/
+#endif
+	    schedule();
+	}
+    }
+    current->state = TASK_RUNNING;
+    remove_wait_queue(&info->open_wait, &wait);
+    if (!tty_hung_up_p(filp)){
+	info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+	printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+	    current->pid, info->count);
+#endif
+    }
+    info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+	   info->line, info->count);/**/
+#endif
+    if (retval)
+	return retval;
+    info->flags |= ASYNC_NORMAL_ACTIVE;
+    return 0;
+} /* block_til_ready */
+
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * performs the serial-specific initialization for the tty structure.
+ */
+int
+cy_open(struct tty_struct *tty, struct file * filp)
+{
+  struct cyclades_port  *info;
+  int retval, line;
+
+    line = MINOR(tty->device) - tty->driver.minor_start;
+    if ((line < 0) || (NR_PORTS <= line)){
+        return -ENODEV;
+    }
+    info = &cy_port[line];
+    if (info->line < 0){
+        return -ENODEV;
+    }
+    
+    /* If the card's firmware hasn't been loaded,
+       treat it as absent from the system.  This
+       will make the user pay attention.
+    */
+    if (IS_CYC_Z(cy_card[info->card])) {
+      struct FIRM_ID *firm_id =
+                (struct FIRM_ID *)
+		(cy_card[info->card].base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
+	    printk("Cyclom-Z firmware not yet loaded\n");
+	    return -ENODEV;
+	}
+    }
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_open ttyC%d\n", info->line); /* */
+#endif
+    if (serial_paranoia_check(info, tty->device, "cy_open")){
+        return -ENODEV;
+    }
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:cy_open ttyC%d, count = %d\n",
+        info->line, info->count);/**/
+#endif
+    info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cy_open (%d): incrementing count to %d\n",
+        current->pid, info->count);
+#endif
+    tty->driver_data = info;
+    info->tty = tty;
+
+    /* Some drivers have (incorrect/incomplete) code to test
+       against a race condition.  Should add good code here!!! */
+    if (!tmp_buf) {
+        tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+        if (!tmp_buf){
+            return -ENOMEM;
+        }
+    }
+
+    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+            *tty->termios = info->normal_termios;
+        else 
+            *tty->termios = info->callout_termios;
+    }
+    /*
+     * Start up serial port
+     */
+    retval = startup(info);
+    if (retval){
+        return retval;
+    }
+
+    MOD_INC_USE_COUNT;
+
+    retval = block_til_ready(tty, filp, info);
+    if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+        printk("cyc:cy_open returning after block_til_ready with %d\n",
+               retval);
 #endif
-        }
-	write_cy_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
-         /* it may be appropriate to clear _XMIT at
-           some later date (after testing)!!! */
+        return retval;
+    }
 
-	if (info->tty){
-	    set_bit(TTY_IO_ERROR, &info->tty->flags);
-	}
-	info->flags &= ~ASYNC_INITIALIZED;
-    restore_flags(flags);
+    info->session = current->session;
+    info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk(" done\n");
+    printk(" cyc:cy_open done\n");/**/
 #endif
-    return;
-} /* shutdown */
+    return 0;
+} /* cy_open */
+
 
 /*
- * This routine finds or computes the various line characteristics.
+ * This routine is called when a particular tty device is closed.
  */
 static void
-config_setup(struct cyclades_port * info)
+cy_close(struct tty_struct * tty, struct file * filp)
 {
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
-  unsigned cflag;
-  int   i;
 
-    if (!info->tty || !info->tty->termios){
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_close ttyC%d\n", info->line);
+#endif
+
+    if (!info
+    || serial_paranoia_check(info, tty->device, "cy_close")){
         return;
     }
-    if (info->line == -1){
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+#endif
+
+    save_flags(flags); cli();
+
+    /* If the TTY is being hung up, nothing to do */
+    if (tty_hung_up_p(filp)) {
+        restore_flags(flags);
         return;
     }
-    cflag = info->tty->termios->c_cflag;
-
-    /* baud rate */
-    i = cflag & CBAUD;
-#ifdef CBAUDEX
-/* Starting with kernel 1.1.65, there is direct support for
-   higher baud rates.  The following code supports those
-   changes.  The conditional aspect allows this driver to be
-   used for earlier as well as later kernel versions.  (The
-   mapping is slightly different from serial.c because there
-   is still the possibility of supporting 75 kbit/sec with
-   the Cyclades board.)
- */
-    if (i & CBAUDEX) {
-	if (i == B57600)
-	    i = 16;
-	else if(i == B115200) 
-	    i = 18;
-#ifdef B78600
-	else if(i == B78600) 
-	    i = 17;
-#endif
-	else
-	    info->tty->termios->c_cflag &= ~CBAUDEX;
+        
+    if ((tty->count == 1) && (info->count != 1)) {
+        /*
+         * Uh, oh.  tty->count is 1, which means that the tty
+         * structure will be freed.  Info->count should always
+         * be one in these conditions.  If it's greater than
+         * one, we've got real problems, since it means the
+         * serial port won't be shutdown.
+         */
+        printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+           "info->count is %d\n", info->count);
+        info->count = 1;
     }
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cy_close at (%d): decrementing count to %d\n",
+        current->pid, info->count - 1);
 #endif
-    if (i == 15) {
-	    if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-		    i += 1;
-	    if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-		    i += 3;
-    }
-    info->tbpr = baud_bpr[i]; /* Tx BPR */
-    info->tco = baud_co[i]; /* Tx CO */
-    info->rbpr = baud_bpr[i]; /* Rx BPR */
-    info->rco = baud_co[i]; /* Rx CO */
-    if (baud_table[i] == 134) {
-        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
-        /* get it right for 134.5 baud */
-    } else if (baud_table[i]) {
-        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
-        /* this needs to be propagated into the card info */
-    } else {
-        info->timeout = 0;
+    if (--info->count < 0) {
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cyc_close setting count to 0\n");
+#endif
+        info->count = 0;
     }
-    /* By tradition (is it a standard?) a baud rate of zero
-       implies the line should be/has been closed.  A bit
-       later in this routine such a test is performed. */
-
-    /* byte size and parity */
-    info->cor5 = 0;
-    info->cor4 = 0;
-    info->cor3 = (info->default_threshold
-		  ? info->default_threshold
-		  : baud_cor3[i]); /* receive threshold */
-    info->cor2 = CyETC;
-    switch(cflag & CSIZE){
-    case CS5:
-        info->cor1 = Cy_5_BITS;
-        break;
-    case CS6:
-        info->cor1 = Cy_6_BITS;
-        break;
-    case CS7:
-        info->cor1 = Cy_7_BITS;
-        break;
-    case CS8:
-        info->cor1 = Cy_8_BITS;
-        break;
-    }
-    if(cflag & CSTOPB){
-        info->cor1 |= Cy_2_STOP;
-    }
-    if (cflag & PARENB){
-        if (cflag & PARODD){
-            info->cor1 |= CyPARITY_O;
-        }else{
-            info->cor1 |= CyPARITY_E;
-        }
-    }else{
-        info->cor1 |= CyPARITY_NONE;
+    if (info->count) {
+        MOD_DEC_USE_COUNT;
+        restore_flags(flags);
+        return;
     }
-	
-    /* CTS flow control flag */
-    if (cflag & CRTSCTS){
-	info->flags |= ASYNC_CTS_FLOW;
-	info->cor2 |= CyCtsAE;
-    }else{
-	info->flags &= ~ASYNC_CTS_FLOW;
-	info->cor2 &= ~CyCtsAE;
+    info->flags |= ASYNC_CLOSING;
+    /*
+     * Save the termios structure, since this port may have
+     * separate termios for callout and dialin.
+     */
+    if (info->flags & ASYNC_NORMAL_ACTIVE)
+        info->normal_termios = *tty->termios;
+    if (info->flags & ASYNC_CALLOUT_ACTIVE)
+        info->callout_termios = *tty->termios;
+    if (info->flags & ASYNC_INITIALIZED)
+        tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+    shutdown(info);
+    if (tty->driver.flush_buffer)
+        tty->driver.flush_buffer(tty);
+    if (tty->ldisc.flush_buffer)
+        tty->ldisc.flush_buffer(tty);
+    info->event = 0;
+    info->tty = 0;
+    if (info->blocked_open) {
+        if (info->close_delay) {
+            current->state = TASK_INTERRUPTIBLE;
+            current->timeout = jiffies + info->close_delay;
+            schedule();
+        }
+        wake_up_interruptible(&info->open_wait);
     }
-    if (cflag & CLOCAL)
-	info->flags &= ~ASYNC_CHECK_CD;
-    else
-	info->flags |= ASYNC_CHECK_CD;
-
-     /***********************************************
-	The hardware option, CyRtsAO, presents RTS when
-	the chip has characters to send.  Since most modems
-	use RTS as reverse (inbound) flow control, this
-	option is not used.  If inbound flow control is
-	necessary, DTR can be programmed to provide the
-	appropriate signals for use with a non-standard
-	cable.  Contact Marcio Saito for details.
-     ***********************************************/
-
-    card = info->card;
-    channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = (u_char)channel;
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+                     ASYNC_CLOSING);
+    wake_up_interruptible(&info->close_wait);
 
-       /* tx and rx baud rate */
+#ifdef SERIAL_DEBUG_OTHER
+    printk(" cyc:cy_close done\n");
+#endif
 
-	base_addr[CyTCOR<<index] = info->tco;
-	base_addr[CyTBPR<<index] = info->tbpr;
-	base_addr[CyRCOR<<index] = info->rco;
-	base_addr[CyRBPR<<index] = info->rbpr;
+    MOD_DEC_USE_COUNT;
+    restore_flags(flags);
+    return;
+} /* cy_close */
 
-	/* set line characteristics  according configuration */
 
-	base_addr[CySCHR1<<index] = START_CHAR(info->tty);
-	base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
-	base_addr[CyCOR1<<index] = info->cor1;
-	base_addr[CyCOR2<<index] = info->cor2;
-	base_addr[CyCOR3<<index] = info->cor3;
-	base_addr[CyCOR4<<index] = info->cor4;
-	base_addr[CyCOR5<<index] = info->cor5;
+/* This routine gets called when tty_write has put something into
+ * the write_queue.  The characters may come from user space or
+ * kernel space.
+ *
+ * This routine will return the number of characters actually
+ * accepted for writing.
+ *
+ * If the port is not already transmitting stuff, start it off by
+ * enabling interrupts.  The interrupt service routine will then
+ * ensure that the characters are sent.
+ * If the port is already active, there is no need to kick it.
+ *
+ */
+static int
+cy_write(struct tty_struct * tty, int from_user,
+           const unsigned char *buf, int count)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
+  int c, total = 0;
 
-	write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+#ifdef SERIAL_DEBUG_IO
+    printk("cyc:cy_write ttyC%d\n", info->line); /* */
+#endif
 
-	base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
+    if (serial_paranoia_check(info, tty->device, "cy_write")){
+        return 0;
+    }
+        
+    if (!tty || !info->xmit_buf || !tmp_buf){
+        return 0;
+    }
 
-	base_addr[CyRTPR<<index] = (info->default_timeout
-			     ? info->default_timeout
-			     : 0x02); /* 10ms rx timeout */
-
-	if (C_CLOCAL(info->tty)) {
-	    base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
-				    /* act on 1->0 modem transitions */
-	    base_addr[CyMCOR1<<index] = CyCTS;
-				    /* act on 0->1 modem transitions */
-	    base_addr[CyMCOR2<<index] = CyCTS;
-	} else {
-	    base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
-				    /* act on 1->0 modem transitions */
-	    base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
-				    /* act on 0->1 modem transitions */
-	    base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
-	}
+    if (from_user)
+	down(&tmp_buf_sem);
+    while (1) {
+        save_flags(flags); cli();               
+        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                           SERIAL_XMIT_SIZE - info->xmit_head));
+        if (c <= 0){
+            restore_flags(flags);
+            break;
+        }
 
-	if(i == 0){ /* baud rate is zero, turn off line */
-	    base_addr[CyMSVR2<<index] = ~CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
-#endif
-	}else{
-	    base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+        if (from_user) {
+            memcpy_fromfs(tmp_buf, buf, c);
+            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                       SERIAL_XMIT_SIZE - info->xmit_head));
+            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+        } else
+            memcpy(info->xmit_buf + info->xmit_head, buf, c);
+        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+        info->xmit_cnt += c;
+        restore_flags(flags);
+        buf += c;
+        count -= c;
+        total += c;
+#if 0
+        SP("CW");
+	CP16(c);
+	SP(" ");
 #endif
-	}
-
-	if (info->tty){
-	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	}
+    }
+    if (from_user)
+	up(&tmp_buf_sem);
 
-    restore_flags(flags);
 
-} /* config_setup */
+    if (info->xmit_cnt
+    && !tty->stopped
+    && !tty->hw_stopped ) {
+        start_xmit(info);
+    }
+    return total;
+} /* cy_write */
 
 
+/*
+ * This routine is called by the kernel to write a single
+ * character to the tty device.  If the kernel uses this routine,
+ * it must call the flush_chars() routine (if defined) when it is
+ * done stuffing characters into the driver.  If there is no room
+ * in the queue, the character is ignored.
+ */
 static void
 cy_put_char(struct tty_struct *tty, unsigned char ch)
 {
@@ -1574,28 +2493,35 @@
   unsigned long flags;
 
 #ifdef SERIAL_DEBUG_IO
-    printk("cy_put_char ttyC%d\n", info->line);
+    printk("cyc:cy_put_char ttyC%d\n", info->line);
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_put_char"))
-	return;
+        return;
 
     if (!tty || !info->xmit_buf)
-	return;
+        return;
 
     save_flags(flags); cli();
-	if (info->xmit_cnt >= PAGE_SIZE - 1) {
-	    restore_flags(flags);
-	    return;
-	}
+        if (info->xmit_cnt >= PAGE_SIZE - 1) {
+            restore_flags(flags);
+            return;
+        }
 
-	info->xmit_buf[info->xmit_head++] = ch;
-	info->xmit_head &= PAGE_SIZE - 1;
-	info->xmit_cnt++;
+        info->xmit_buf[info->xmit_head++] = ch;
+        info->xmit_head &= PAGE_SIZE - 1;
+        info->xmit_cnt++;
     restore_flags(flags);
+#if 0
+	SP("+");
+#endif
 } /* cy_put_char */
 
 
+/*
+ * This routine is called by the kernel after it has written a
+ * series of characters to the tty device using put_char().  
+ */
 static void
 cy_flush_chars(struct tty_struct *tty)
 {
@@ -1603,110 +2529,60 @@
   unsigned long flags;
   unsigned char *base_addr;
   int card,chip,channel,index;
-				
+                                
 #ifdef SERIAL_DEBUG_IO
-    printk("cy_flush_chars ttyC%d\n", info->line); /* */
+    printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
-	return;
+        return;
 
     if (info->xmit_cnt <= 0 || tty->stopped
     || tty->hw_stopped || !info->xmit_buf)
-	return;
+        return;
 
     card = info->card;
     channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = channel;
-	base_addr[CySRER<<index] |= CyTxMpty;
-    restore_flags(flags);
-} /* cy_flush_chars */
-
-
-/* This routine gets called when tty_write has put something into
-    the write_queue.  If the port is not already transmitting stuff,
-    start it off by enabling interrupts.  The interrupt service
-    routine will then ensure that the characters are sent.  If the
-    port is already active, there is no need to kick it.
- */
-static int
-cy_write(struct tty_struct * tty, int from_user,
-           const unsigned char *buf, int count)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-  int c, total = 0;
-
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_write ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_write")){
-	return 0;
-    }
-	
-    if (!tty || !info->xmit_buf || !tmp_buf){
-        return 0;
-    }
-
-    while (1) {
-        save_flags(flags); cli();		
-	c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-			   SERIAL_XMIT_SIZE - info->xmit_head));
-	if (c <= 0){
-	    restore_flags(flags);
-	    break;
-	}
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
-	if (from_user) {
-	    down(&tmp_buf_sem);
-	    copy_from_user(tmp_buf, buf, c);
-	    c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-		       SERIAL_XMIT_SIZE - info->xmit_head));
-	    memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-	    up(&tmp_buf_sem);
-	} else
-	    memcpy(info->xmit_buf + info->xmit_head, buf, c);
-	info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-	info->xmit_cnt += c;
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = channel;
+	    base_addr[CySRER<<index] |= CyTxMpty;
 	restore_flags(flags);
-	buf += c;
-	count -= c;
-	total += c;
-    }
-
-
-    if (info->xmit_cnt
-    && !tty->stopped
-    && !tty->hw_stopped ) {
-        start_xmit(info);
+    } else {
+	/* Since polling is already in place,
+	    nothing further need be done.  */
     }
-    return total;
-} /* cy_write */
+} /* cy_flush_chars */
 
 
+/*
+ * This routine returns the numbers of characters the tty driver
+ * will accept for queuing to be written.  This number is subject
+ * to change as output buffers get emptied, or if the output flow
+ * control is activated.
+ */
 static int
 cy_write_room(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  int	ret;
-				
+  int   ret;
+                                
 #ifdef SERIAL_DEBUG_IO
-    printk("cy_write_room ttyC%d\n", info->line); /* */
+    printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_write_room"))
-	return 0;
+        return 0;
     ret = PAGE_SIZE - info->xmit_cnt - 1;
     if (ret < 0)
-	ret = 0;
+        ret = 0;
     return ret;
 } /* cy_write_room */
 
@@ -1715,126 +2591,351 @@
 cy_chars_in_buffer(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-				
+                                
 #ifdef SERIAL_DEBUG_IO
-    printk("cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
+    printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+        info->line, info->xmit_cnt); /* */
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
-	return 0;
+        return 0;
 
     return info->xmit_cnt;
 } /* cy_chars_in_buffer */
 
 
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-				
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
-	return;
-    save_flags(flags); cli();
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-    restore_flags(flags);
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-	(tty->ldisc.write_wakeup)(tty);
-} /* cy_flush_buffer */
+/*
+ * ------------------------------------------------------------
+ * cy_ioctl() and friends
+ * ------------------------------------------------------------
+ */
 
 
-/* This routine is called by the upper-layer tty layer to signal
-   that incoming characters should be throttled or that the
-   throttle should be released.
+/*
+ * This routine finds or computes the various line characteristics.
+ * It used to be called config_setup
  */
 static void
-cy_throttle(struct tty_struct * tty)
+set_line_char(struct cyclades_port * info)
 {
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
   unsigned char *base_addr;
   int card,chip,channel,index;
+  unsigned cflag;
+  int   i;
+
+    if (!info->tty || !info->tty->termios){
+        return;
+    }
+    if (info->line == -1){
+        return;
+    }
+    cflag = info->tty->termios->c_cflag;
+
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
+    if (!IS_CYC_Z(cy_card[card])) {
+	/* baud rate */
+	i = cflag & CBAUD;
+     
+	if (i & CBAUDEX) {
+	    if (i == B57600)
+		i = 16;
+	    else if(i == B115200) 
+		i = 18;
+#ifdef B76800
+	    else if(i == B76800) 
+		i = 17;
+#endif
+	    else
+		info->tty->termios->c_cflag &= ~CBAUDEX;
+	}
+
+	if (i == 15) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			i += 1;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			i += 3;
+	}
+	info->tbpr = baud_bpr[i]; /* Tx BPR */
+	info->tco = baud_co[i]; /* Tx CO */
+	info->rbpr = baud_bpr[i]; /* Rx BPR */
+	info->rco = baud_co[i]; /* Rx CO */
+	if (baud_table[i] == 134) {
+	    info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+	    /* get it right for 134.5 baud */
+	} else if (baud_table[i]) {
+	    info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
+	    /* this needs to be propagated into the card info */
+	} else {
+	    info->timeout = 0;
+	}
+	/* By tradition (is it a standard?) a baud rate of zero
+	   implies the line should be/has been closed.  A bit
+	   later in this routine such a test is performed. */
+
+	/* byte size and parity */
+	info->cor5 = 0;
+	info->cor4 = 0;
+	info->cor3 = (info->default_threshold
+		      ? info->default_threshold
+		      : baud_cor3[i]); /* receive threshold */
+	info->cor2 = CyETC;
+	switch(cflag & CSIZE){
+	case CS5:
+	    info->cor1 = Cy_5_BITS;
+	    break;
+	case CS6:
+	    info->cor1 = Cy_6_BITS;
+	    break;
+	case CS7:
+	    info->cor1 = Cy_7_BITS;
+	    break;
+	case CS8:
+	    info->cor1 = Cy_8_BITS;
+	    break;
+	}
+	if(cflag & CSTOPB){
+	    info->cor1 |= Cy_2_STOP;
+	}
+	if (cflag & PARENB){
+	    if (cflag & PARODD){
+		info->cor1 |= CyPARITY_O;
+	    }else{
+		info->cor1 |= CyPARITY_E;
+	    }
+	}else{
+	    info->cor1 |= CyPARITY_NONE;
+	}
+	    
+	/* CTS flow control flag */
+	if (cflag & CRTSCTS){
+	    info->flags |= ASYNC_CTS_FLOW;
+	    info->cor2 |= CyCtsAE;
+	}else{
+	    info->flags &= ~ASYNC_CTS_FLOW;
+	    info->cor2 &= ~CyCtsAE;
+	}
+	if (cflag & CLOCAL)
+	    info->flags &= ~ASYNC_CHECK_CD;
+	else
+	    info->flags |= ASYNC_CHECK_CD;
+
+	 /***********************************************
+	    The hardware option, CyRtsAO, presents RTS when
+	    the chip has characters to send.  Since most modems
+	    use RTS as reverse (inbound) flow control, this
+	    option is not used.  If inbound flow control is
+	    necessary, DTR can be programmed to provide the
+	    appropriate signals for use with a non-standard
+	    cable.  Contact Marcio Saito for details.
+	 ***********************************************/
+
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = (u_char)channel;
 
-#ifdef SERIAL_DEBUG_THROTTLE
-  char buf[64];
-	
-    printk("throttle %s: %d....\n", _tty_name(tty, buf),
-	   tty->ldisc.chars_in_buffer(tty));
-    printk("cy_throttle ttyC%d\n", info->line);
+	   /* tx and rx baud rate */
+
+	    base_addr[CyTCOR<<index] = info->tco;
+	    base_addr[CyTBPR<<index] = info->tbpr;
+	    base_addr[CyRCOR<<index] = info->rco;
+	    base_addr[CyRBPR<<index] = info->rbpr;
+
+	    /* set line characteristics  according configuration */
+
+	    base_addr[CySCHR1<<index] = START_CHAR(info->tty);
+	    base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
+	    base_addr[CyCOR1<<index] = info->cor1;
+	    base_addr[CyCOR2<<index] = info->cor2;
+	    base_addr[CyCOR3<<index] = info->cor3;
+	    base_addr[CyCOR4<<index] = info->cor4;
+	    base_addr[CyCOR5<<index] = info->cor5;
+
+	    cyy_issue_cmd(base_addr,
+		     CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+
+	    base_addr[CyCAR<<index] =
+				(u_char)channel; /* !!! Is this needed? */
+
+	    base_addr[CyRTPR<<index] = (info->default_timeout
+					 ? info->default_timeout
+					 : 0x02); /* 10ms rx timeout */
+
+	    if (C_CLOCAL(info->tty)) {
+		base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
+					/* act on 1->0 modem transitions */
+		base_addr[CyMCOR1<<index] = CyCTS;
+					/* act on 0->1 modem transitions */
+		base_addr[CyMCOR2<<index] = CyCTS;
+	    } else {
+		base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
+					/* act on 1->0 modem transitions */
+		base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+					/* act on 0->1 modem transitions */
+		base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+	    }
+
+	    if(i == 0){ /* baud rate is zero, turn off line */
+		base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc:set_line_char dropping DTR\n");
+		printk("     status: 0x%x,
+		    0x%x\n", base_addr[CyMSVR1<<index],
+		    base_addr[CyMSVR2<<index]);
+#endif
+	    }else{
+		base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc:set_line_char raising DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index],
+		    base_addr[CyMSVR2<<index]);
 #endif
+	    }
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+	    if (info->tty){
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	    }
+
+	restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      struct BUF_CTRL *buf_ctrl;
+      int retval;
+
+        firm_id = (struct FIRM_ID *)
+			(cy_card[card].base_addr + ID_ADDRESS);
+        if (firm_id->signature != ZFIRM_ID){
 	    return;
-    }
+	}
 
-    if (I_IXOFF(tty)) {
-	info->x_char = STOP_CHAR(tty);
-	    /* Should use the "Send Special Character" feature!!! */
-    }
+	zfw_ctrl =
+            (struct ZFW_CTRL *)
+                (cy_card[card].base_addr + firm_id->zfwctrl_addr);
+	board_ctrl = &zfw_ctrl->board_ctrl;
+	ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
+	buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
 
-    card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+	/* baud rate */
+	switch(i = cflag & CBAUD){
+	/*
+        case B0: ch_ctrl->comm_baud = 0; break;
+	*/
+        case B50: ch_ctrl->comm_baud = 50; break;
+        case B75: ch_ctrl->comm_baud = 75; break;
+        case B110: ch_ctrl->comm_baud = 110; break;
+        case B134: ch_ctrl->comm_baud = 134; break;
+        case B150: ch_ctrl->comm_baud = 150; break;
+        case B200: ch_ctrl->comm_baud = 200; break;
+        case B300: ch_ctrl->comm_baud = 300; break;
+        case B600: ch_ctrl->comm_baud = 600; break;
+        case B1200: ch_ctrl->comm_baud = 1200; break;
+        case B1800: ch_ctrl->comm_baud = 1800; break;
+        case B2400: ch_ctrl->comm_baud = 2400; break;
+        case B4800: ch_ctrl->comm_baud = 4800; break;
+        case B9600: ch_ctrl->comm_baud = 9600; break;
+        case B19200: ch_ctrl->comm_baud = 19200; break;
+        case B38400:
+            if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
+                ch_ctrl->comm_baud = 57600;
+            }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
+                ch_ctrl->comm_baud = 115200;
+            }else{
+                ch_ctrl->comm_baud = 38400;
+            }
+            break;
+        case B57600: ch_ctrl->comm_baud = 57600; break;
+#ifdef B76800
+        case B76800: ch_ctrl->comm_baud = 76800; break;
+#endif
+        case B115200: ch_ctrl->comm_baud = 115200; break;
+        case B230400: ch_ctrl->comm_baud = 230400; break;
+        case B460800: ch_ctrl->comm_baud = 460800; break;
+	}
+        if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
+                ch_ctrl->comm_baud = info->baud;
+        }
 
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = (u_char)channel;
-	base_addr[CyMSVR1<<index] = ~CyRTS;
-    restore_flags(flags);
+	/* byte size and parity */
+	switch(cflag & CSIZE){
+	case CS5: ch_ctrl->comm_data_l = C_DL_CS5; break;
+	case CS6: ch_ctrl->comm_data_l = C_DL_CS6; break;
+	case CS7: ch_ctrl->comm_data_l = C_DL_CS7; break;
+	case CS8: ch_ctrl->comm_data_l = C_DL_CS8; break;
+	}
+	if(cflag & CSTOPB){
+	    ch_ctrl->comm_data_l |= C_DL_2STOP;
+	}else{
+	    ch_ctrl->comm_data_l |= C_DL_1STOP;
+	}
+	if (cflag & PARENB){
+	    if (cflag & PARODD){
+		ch_ctrl->comm_parity = C_PR_ODD;
+	    }else{
+		ch_ctrl->comm_parity = C_PR_EVEN;
+	    }
+	}else{
+	    ch_ctrl->comm_parity = C_PR_NONE;
+	}
 
-    return;
-} /* cy_throttle */
+	/* CTS flow control flag */
+	if (cflag & CRTSCTS){
+	    info->flags |= ASYNC_CTS_FLOW;
+	    ch_ctrl->hw_flow |= C_RS_CTS | C_RS_RTS;
+	}else{
+	    info->flags &= ~ASYNC_CTS_FLOW;
+	    ch_ctrl->hw_flow &= ~(C_RS_CTS | C_RS_RTS);
+	}
 
+	retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+	if (retval != 0){
+	    printk("cyc:set_line_char retval at %d was %x\n",
+	        __LINE__, retval);
+	}
 
-static void
-cy_unthrottle(struct tty_struct * tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
+	/* CD sensitivity */
+	if (cflag & CLOCAL){
+	    info->flags &= ~ASYNC_CHECK_CD;
+	}else{
+	    info->flags |= ASYNC_CHECK_CD;
+	}
 
-#ifdef SERIAL_DEBUG_THROTTLE
-  char buf[64];
-	
-    printk("throttle %s: %d....\n", _tty_name(tty, buf),
-	   tty->ldisc.chars_in_buffer(tty));
-    printk("cy_unthrottle ttyC%d\n", info->line);
+	if(i == 0){ /* baud rate is zero, turn off line */
+	    ch_ctrl->rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+	    printk("cyc:set_line_char dropping Z DTR\n");
+#endif
+	}else{
+	    ch_ctrl->rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+	    printk("cyc:set_line_char raising Z DTR\n");
 #endif
+	}
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
-	    return;
-    }
+	retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
+	if (retval != 0){
+	    printk("cyc:set_line_char retval at %d was %x\n",
+	        __LINE__, retval);
+	}
 
-    if (I_IXOFF(tty)) {
-	info->x_char = START_CHAR(tty);
-	/* Should use the "Send Special Character" feature!!! */
+	if (info->tty){
+	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	}
     }
 
-    card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
-    save_flags(flags); cli();
-	base_addr[CyCAR<<index] = (u_char)channel;
-	base_addr[CyMSVR1<<index] = CyRTS;
-    restore_flags(flags);
+} /* set_line_char */
 
-    return;
-} /* cy_unthrottle */
 
 static int
 get_serial_info(struct cyclades_port * info,
@@ -1851,14 +2952,15 @@
     tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
     tmp.irq = cinfo->irq;
     tmp.flags = info->flags;
-    tmp.baud_base = 0;          /*!!!*/
     tmp.close_delay = info->close_delay;
+    tmp.baud_base = info->baud;
     tmp.custom_divisor = 0;     /*!!!*/
     tmp.hub6 = 0;               /*!!!*/
-    copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
     return 0;
 } /* get_serial_info */
 
+
 static int
 set_serial_info(struct cyclades_port * info,
                            struct serial_struct * new_info)
@@ -1867,18 +2969,19 @@
   struct cyclades_port old_info;
 
     if (!new_info)
-	    return -EFAULT;
-    copy_from_user(&new_serial,new_info,sizeof(new_serial));
+            return -EFAULT;
+    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
     old_info = *info;
 
     if (!suser()) {
-	    if ((new_serial.close_delay != info->close_delay) ||
-		((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
-		 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
-		    return -EPERM;
-	    info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-			   (new_serial.flags & ASYNC_USR_MASK));
-	    goto check_and_exit;
+            if ((new_serial.close_delay != info->close_delay) ||
+                ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+                 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+                    return -EPERM;
+            info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                           (new_serial.flags & ASYNC_USR_MASK));
+            info->baud = new_serial.baud_base;
+            goto check_and_exit;
     }
 
 
@@ -1888,19 +2991,21 @@
      */
 
     info->flags = ((info->flags & ~ASYNC_FLAGS) |
-		    (new_serial.flags & ASYNC_FLAGS));
+                    (new_serial.flags & ASYNC_FLAGS));
+    info->baud = new_serial.baud_base;
     info->close_delay = new_serial.close_delay;
 
 
 check_and_exit:
     if (info->flags & ASYNC_INITIALIZED){
-	config_setup(info);
-	return 0;
+        set_line_char(info);
+        return 0;
     }else{
         return startup(info);
     }
 } /* set_serial_info */
 
+
 static int
 get_modem_info(struct cyclades_port * info, unsigned int *value)
 {
@@ -1908,259 +3013,423 @@
   unsigned char *base_addr;
   unsigned long flags;
   unsigned char status;
+  unsigned long lstatus;
   unsigned int result;
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  struct CH_CTRL *ch_ctrl;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
-    save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)channel;
-        status = base_addr[CyMSVR1<<index];
-	status |= base_addr[CyMSVR2<<index];
-    restore_flags(flags);
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = (u_char)channel;
+	    status = base_addr[CyMSVR1<<index];
+	    status |= base_addr[CyMSVR2<<index];
+	restore_flags(flags);
+
+	result =  ((status  & CyRTS) ? TIOCM_RTS : 0)
+		| ((status  & CyDTR) ? TIOCM_DTR : 0)
+		| ((status  & CyDCD) ? TIOCM_CAR : 0)
+		| ((status  & CyRI) ? TIOCM_RNG : 0)
+		| ((status  & CyDSR) ? TIOCM_DSR : 0)
+		| ((status  & CyCTS) ? TIOCM_CTS : 0);
+    } else {
+	base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+        if (cy_card[card].num_chips != 1){
+	    return -EINVAL;
+	}
+
+	firm_id = (struct FIRM_ID *)
+		    (cy_card[card].base_addr + ID_ADDRESS);
+	if (firm_id->signature == ZFIRM_ID){
+	    zfw_ctrl =
+		(struct ZFW_CTRL *)
+		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
+	    board_ctrl = &zfw_ctrl->board_ctrl;
+	    ch_ctrl = zfw_ctrl->ch_ctrl;
+	    lstatus = ch_ctrl[channel].rs_status;
+	    result =  ((lstatus  & C_RS_RTS) ? TIOCM_RTS : 0)
+		    | ((lstatus  & C_RS_DTR) ? TIOCM_DTR : 0)
+	            | ((lstatus  & C_RS_DCD) ? TIOCM_CAR : 0)
+		    | ((lstatus  & C_RS_RI) ? TIOCM_RNG : 0)
+		    | ((lstatus  & C_RS_DSR) ? TIOCM_DSR : 0)
+		    | ((lstatus  & C_RS_CTS) ? TIOCM_CTS : 0);
+	}else{
+	    result = 0;
+	    return -ENODEV;
+	}
 
-    result =  ((status  & CyRTS) ? TIOCM_RTS : 0)
-            | ((status  & CyDTR) ? TIOCM_DTR : 0)
-            | ((status  & CyDCD) ? TIOCM_CAR : 0)
-            | ((status  & CyRI) ? TIOCM_RNG : 0)
-            | ((status  & CyDSR) ? TIOCM_DSR : 0)
-            | ((status  & CyCTS) ? TIOCM_CTS : 0);
-    put_user(result,(unsigned int *) value);
+    }
+    put_fs_long(result,(unsigned long *) value);
     return 0;
 } /* get_modem_info */
 
+
 static int
 set_modem_info(struct cyclades_port * info, unsigned int cmd,
                           unsigned int *value)
 {
-    int card,chip,channel,index;
-    unsigned char *base_addr;
-    unsigned long flags;
-    unsigned int arg;
-    int error;
-  
-    error = get_user(arg, value);
-    if (error)
-	return error;
+  int card,chip,channel,index;
+  unsigned char *base_addr;
+  unsigned long flags;
+  unsigned int arg = get_fs_long((unsigned long *) value);
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  struct CH_CTRL *ch_ctrl;
+  int retval;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
-    switch (cmd) {
-    case TIOCMBIS:
-	if (arg & TIOCM_RTS){
-	    save_flags(flags); cli();
+	switch (cmd) {
+	case TIOCMBIS:
+	    if (arg & TIOCM_RTS){
+		save_flags(flags); cli();
+		    base_addr[CyCAR<<index] = (u_char)channel;
+		    base_addr[CyMSVR1<<index] = CyRTS;
+		restore_flags(flags);
+	    }
+	    if (arg & TIOCM_DTR){
+		save_flags(flags); cli();
 		base_addr[CyCAR<<index] = (u_char)channel;
-		base_addr[CyMSVR1<<index] = CyRTS;
-	    restore_flags(flags);
-	}
-	if (arg & TIOCM_DTR){
-	    save_flags(flags); cli();
-	    base_addr[CyCAR<<index] = (u_char)channel;
-	    base_addr[CyMSVR2<<index] = CyDTR;
+		base_addr[CyMSVR2<<index] = CyDTR;
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+		printk("cyc:set_modem_info raising DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
 #endif
-	    restore_flags(flags);
-	}
-	break;
-    case TIOCMBIC:
-	if (arg & TIOCM_RTS){
-	    save_flags(flags); cli();
+		restore_flags(flags);
+	    }
+	    break;
+	case TIOCMBIC:
+	    if (arg & TIOCM_RTS){
+		save_flags(flags); cli();
+		    base_addr[CyCAR<<index] = (u_char)channel;
+		    base_addr[CyMSVR1<<index] = ~CyRTS;
+		restore_flags(flags);
+	    }
+	    if (arg & TIOCM_DTR){
+		save_flags(flags); cli();
 		base_addr[CyCAR<<index] = (u_char)channel;
-		base_addr[CyMSVR1<<index] = ~CyRTS;
-	    restore_flags(flags);
-	}
-	if (arg & TIOCM_DTR){
-	    save_flags(flags); cli();
-	    base_addr[CyCAR<<index] = (u_char)channel;
-	    base_addr[CyMSVR2<<index] = ~CyDTR;
+		base_addr[CyMSVR2<<index] = ~CyDTR;
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+		printk("cyc:set_modem_info dropping DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
 #endif
-	    restore_flags(flags);
-	}
-	break;
-    case TIOCMSET:
-	if (arg & TIOCM_RTS){
-	    save_flags(flags); cli();
+		restore_flags(flags);
+	    }
+	    break;
+	case TIOCMSET:
+	    if (arg & TIOCM_RTS){
+		save_flags(flags); cli();
+		    base_addr[CyCAR<<index] = (u_char)channel;
+		    base_addr[CyMSVR1<<index] = CyRTS;
+		restore_flags(flags);
+	    }else{
+		save_flags(flags); cli();
+		    base_addr[CyCAR<<index] = (u_char)channel;
+		    base_addr[CyMSVR1<<index] = ~CyRTS;
+		restore_flags(flags);
+	    }
+	    if (arg & TIOCM_DTR){
+		save_flags(flags); cli();
 		base_addr[CyCAR<<index] = (u_char)channel;
-		base_addr[CyMSVR1<<index] = CyRTS;
-	    restore_flags(flags);
-	}else{
-	    save_flags(flags); cli();
+		base_addr[CyMSVR2<<index] = CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc:set_modem_info raising DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+		restore_flags(flags);
+	    }else{
+		save_flags(flags); cli();
 		base_addr[CyCAR<<index] = (u_char)channel;
-		base_addr[CyMSVR1<<index] = ~CyRTS;
-	    restore_flags(flags);
+		base_addr[CyMSVR2<<index] = ~CyDTR;
+#ifdef SERIAL_DEBUG_DTR
+		printk("cyc:set_modem_info dropping DTR\n");
+		printk("     status: 0x%x, 0x%x\n",
+		    base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+#endif
+		restore_flags(flags);
+	    }
+	    break;
+	default:
+	    return -EINVAL;
 	}
-	if (arg & TIOCM_DTR){
-	    save_flags(flags); cli();
-	    base_addr[CyCAR<<index] = (u_char)channel;
-	    base_addr[CyMSVR2<<index] = CyDTR;
+    } else {
+	base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+	firm_id = (struct FIRM_ID *)
+		    (cy_card[card].base_addr + ID_ADDRESS);
+	if (firm_id->signature == ZFIRM_ID){
+	    zfw_ctrl =
+		(struct ZFW_CTRL *)
+		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
+	    board_ctrl = &zfw_ctrl->board_ctrl;
+	    ch_ctrl = zfw_ctrl->ch_ctrl;
+
+	    switch (cmd) {
+	    case TIOCMBIS:
+		if (arg & TIOCM_RTS){
+		    ch_ctrl[channel].rs_control |= C_RS_RTS;
+		}
+		if (arg & TIOCM_DTR){
+		    ch_ctrl[channel].rs_control |= C_RS_DTR;
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+		    printk("cyc:set_modem_info raising Z DTR\n");
 #endif
-	    restore_flags(flags);
-	}else{
-	    save_flags(flags); cli();
-	    base_addr[CyCAR<<index] = (u_char)channel;
-	    base_addr[CyMSVR2<<index] = ~CyDTR;
+		}
+		break;
+	    case TIOCMBIC:
+		if (arg & TIOCM_RTS){
+		    ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+		}
+		if (arg & TIOCM_DTR){
+		    ch_ctrl[channel].rs_control &= ~C_RS_DTR;
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+		    printk("cyc:set_modem_info clearing Z DTR\n");
 #endif
-	    restore_flags(flags);
-	}
-	break;
-    default:
+		}
+		break;
+	    case TIOCMSET:
+		if (arg & TIOCM_RTS){
+		    ch_ctrl[channel].rs_control |= C_RS_RTS;
+		}else{
+		    ch_ctrl[channel].rs_control &= ~C_RS_RTS;
+		}
+		if (arg & TIOCM_DTR){
+		    ch_ctrl[channel].rs_control |= C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+		    printk("cyc:set_modem_info raising Z DTR\n");
+#endif
+		}else{
+		    ch_ctrl[channel].rs_control &= ~C_RS_DTR;
+#ifdef SERIAL_DEBUG_DTR
+		    printk("cyc:set_modem_info clearing Z DTR\n");
+#endif
+		}
+		break;
+	    default:
 		return -EINVAL;
-        }
+	    }
+	}else{
+	    return -ENODEV;
+	}
+        retval = cyz_issue_cmd(&cy_card[info->card],
+				    channel, C_CM_IOCTLM,0L);
+	if (retval != 0){
+	    printk("cyc:set_modem_info retval at %d was %x\n",
+	        __LINE__, retval);
+	}
+    }
     return 0;
 } /* set_modem_info */
 
+
 static void
 send_break( struct cyclades_port * info, int duration)
-{ /* Let the transmit ISR take care of this (since it
-     requires stuffing characters into the output stream).
-   */
-    info->x_break = duration;
-    if (!info->xmit_cnt ) {
-	start_xmit(info);
+{
+
+    if (!IS_CYC_Z(cy_card[info->card])) {
+        /* Let the transmit ISR take care of this (since it
+	   requires stuffing characters into the output stream).
+        */
+	info->x_break = duration;
+	if (!info->xmit_cnt ) {
+	    start_xmit(info);
+	}
+    } else {
+	/* For the moment we ignore the duration parameter!!!
+	   A better implementation will use C_CM_SET_BREAK
+	   and C_CM_CLR_BREAK with the appropriate delay.
+	 */
+#if 0
+this appears to wedge the output data stream
+int retval;
+        retval = cyz_issue_cmd(&cy_card[info->card],
+		(info->line) - (cy_card[info->card].first_line),
+		C_CM_SENDBRK, 0L);
+	if (retval != 0){
+	    printk("cyc:send_break retval at %d was %x\n",
+	        __LINE__, retval);
+	}
+#endif
     }
 } /* send_break */
 
+
 static int
 get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
 {
 
-   copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
-   info->mon.int_count  = 0;
-   info->mon.char_count = 0;
-   info->mon.char_max   = 0;
-   info->mon.char_last  = 0;
-   return 0;
-}
+    memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor));
+    info->mon.int_count  = 0;
+    info->mon.char_count = 0;
+    info->mon.char_max   = 0;
+    info->mon.char_last  = 0;
+    return 0;
+}/* get_mon_info */
+
 
 static int
 set_threshold(struct cyclades_port * info, unsigned long value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	info->cor3 &= ~CyREC_FIFO;
+	info->cor3 |= value & CyREC_FIFO;
+	base_addr[CyCOR3<<index] = info->cor3;
+	cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+    } else {
+	// Nothing to do!
+    }
+    return 0;
+}/* set_threshold */
 
-   info->cor3 &= ~CyREC_FIFO;
-   info->cor3 |= value & CyREC_FIFO;
-   base_addr[CyCOR3<<index] = info->cor3;
-   write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
-   return 0;
-}
 
 static int
 get_threshold(struct cyclades_port * info, unsigned long *value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
-   unsigned long tmp;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
+  unsigned long tmp;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
+	put_fs_long(tmp,value);
+    } else {
+	// Nothing to do!
+    }
+    return 0;
+}/* get_threshold */
 
-   tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
-   put_user(tmp,value);
-   return 0;
-}
 
 static int
 set_default_threshold(struct cyclades_port * info, unsigned long value)
 {
-   info->default_threshold = value & 0x0f;
-   return 0;
-}
+    info->default_threshold = value & 0x0f;
+    return 0;
+}/* set_default_threshold */
+
 
 static int
 get_default_threshold(struct cyclades_port * info, unsigned long *value)
 {
-   put_user(info->default_threshold,value);
-   return 0;
-}
+    put_fs_long(info->default_threshold,value);
+    return 0;
+}/* get_default_threshold */
+
 
 static int
 set_timeout(struct cyclades_port * info, unsigned long value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	base_addr[CyRTPR<<index] = value & 0xff;
+    } else {
+	// Nothing to do!
+    }
+    return 0;
+}/* set_timeout */
 
-   base_addr[CyRTPR<<index] = value & 0xff;
-   return 0;
-}
 
 static int
 get_timeout(struct cyclades_port * info, unsigned long *value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
-   unsigned long tmp;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
+  unsigned long tmp;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-		   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	tmp = base_addr[CyRTPR<<index];
+	put_fs_long(tmp,value);
+    } else {
+	// Nothing to do!
+    }
+    return 0;
+}/* get_timeout */
 
-   tmp = base_addr[CyRTPR<<index];
-   put_user(tmp,value);
-   return 0;
-}
 
 static int
 set_default_timeout(struct cyclades_port * info, unsigned long value)
 {
-   info->default_timeout = value & 0xff;
-   return 0;
-}
+    info->default_timeout = value & 0xff;
+    return 0;
+}/* set_default_timeout */
+
 
 static int
 get_default_timeout(struct cyclades_port * info, unsigned long *value)
 {
-   put_user(info->default_timeout,value);
-   return 0;
-}
+    put_fs_long(info->default_timeout,value);
+    return 0;
+}/* get_default_timeout */
+
 
+/*
+ * This routine allows the tty driver to implement device-
+ * specific ioctl's.  If the ioctl number passed in cmd is
+ * not recognized by the driver, it should return ENOIOCTLCMD.
+ */
 static int
 cy_ioctl(struct tty_struct *tty, struct file * file,
             unsigned int cmd, unsigned long arg)
@@ -2170,7 +3439,8 @@
   int ret_val = 0;
 
 #ifdef SERIAL_DEBUG_OTHER
-    printk("cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+    printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+        info->line, cmd, arg); /* */
 #endif
 
     switch (cmd) {
@@ -2182,7 +3452,7 @@
                 break;
             }
             ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
-	    break;
+            break;
         case CYGETTHRESH:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2190,11 +3460,11 @@
                 ret_val = error;
                 break;
             }
-	    ret_val = get_threshold(info, (unsigned long *)arg);
- 	    break;
+            ret_val = get_threshold(info, (unsigned long *)arg);
+            break;
         case CYSETTHRESH:
             ret_val = set_threshold(info, (unsigned long)arg);
-	    break;
+            break;
         case CYGETDEFTHRESH:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2202,11 +3472,11 @@
                 ret_val = error;
                 break;
             }
-	    ret_val = get_default_threshold(info, (unsigned long *)arg);
- 	    break;
+            ret_val = get_default_threshold(info, (unsigned long *)arg);
+            break;
         case CYSETDEFTHRESH:
             ret_val = set_default_threshold(info, (unsigned long)arg);
-	    break;
+            break;
         case CYGETTIMEOUT:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2214,11 +3484,11 @@
                 ret_val = error;
                 break;
             }
-	    ret_val = get_timeout(info, (unsigned long *)arg);
- 	    break;
+            ret_val = get_timeout(info, (unsigned long *)arg);
+            break;
         case CYSETTIMEOUT:
             ret_val = set_timeout(info, (unsigned long)arg);
-	    break;
+            break;
         case CYGETDEFTIMEOUT:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2226,23 +3496,23 @@
                 ret_val = error;
                 break;
             }
-	    ret_val = get_default_timeout(info, (unsigned long *)arg);
- 	    break;
+            ret_val = get_default_timeout(info, (unsigned long *)arg);
+            break;
         case CYSETDEFTIMEOUT:
             ret_val = set_default_timeout(info, (unsigned long)arg);
-	    break;
+            break;
         case TCSBRK:    /* SVID version: non-zero arg --> no break */
-	    ret_val = tty_check_change(tty);
-	    if (ret_val)
-		return ret_val;
+            ret_val = tty_check_change(tty);
+            if (ret_val)
+                return ret_val;
             tty_wait_until_sent(tty,0);
             if (!arg)
                 send_break(info, HZ/4); /* 1/4 second */
             break;
         case TCSBRKP:   /* support for POSIX tcsendbreak() */
-	    ret_val = tty_check_change(tty);
-	    if (ret_val)
-		return ret_val;
+            ret_val = tty_check_change(tty);
+            if (ret_val)
+                return ret_val;
             tty_wait_until_sent(tty,0);
             send_break(info, arg ? arg*(HZ/10) : HZ/4);
             break;
@@ -2254,19 +3524,31 @@
 
 /* The following commands are incompletely implemented!!! */
         case TIOCGSOFTCAR:
-            ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
-	    break;
+            error = verify_area(VERIFY_WRITE, (void *) arg
+                                ,sizeof(unsigned int *));
+            if (error){
+                ret_val = error;
+                break;
+            }
+            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+                        (unsigned long *) arg);
+            break;
         case TIOCSSOFTCAR:
-            ret_val = get_user(arg,(unsigned int *) arg);
-	    if (ret_val)
-		break;
+           error = verify_area(VERIFY_READ, (void *) arg
+                                ,sizeof(unsigned long *));
+           if (error) {
+                ret_val = error;
+                break;
+           }
+
+            arg = get_fs_long((unsigned long *) arg);
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) |
                      (arg ? CLOCAL : 0));
             break;
         case TIOCMGET:
             error = verify_area(VERIFY_WRITE, (void *) arg
-                                ,sizeof(unsigned int));
+                                ,sizeof(unsigned int *));
             if (error){
                 ret_val = error;
                 break;
@@ -2294,31 +3576,35 @@
                                    (struct serial_struct *) arg);
             break;
         default:
-	    ret_val = -ENOIOCTLCMD;
+            ret_val = -ENOIOCTLCMD;
     }
 
 #ifdef SERIAL_DEBUG_OTHER
-    printk("cy_ioctl done\n");
+    printk(" cyc:cy_ioctl done\n");
 #endif
 
     return ret_val;
 } /* cy_ioctl */
 
 
-
-
+/*
+ * This routine allows the tty driver to be notified when
+ * device's termios settings have changed.  Note that a
+ * well-designed tty driver should be prepared to accept the case
+ * where old == NULL, and try to do something rational.
+ */
 static void
 cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
 
 #ifdef SERIAL_DEBUG_OTHER
-    printk("cy_set_termios ttyC%d\n", info->line);
+    printk("cyc:cy_set_termios ttyC%d\n", info->line);
 #endif
 
     if (tty->termios->c_cflag == old_termios->c_cflag)
         return;
-    config_setup(info);
+    set_line_char(info);
 
     if ((old_termios->c_cflag & CRTSCTS) &&
         !(tty->termios->c_cflag & CRTSCTS)) {
@@ -2335,353 +3621,243 @@
 } /* cy_set_termios */
 
 
+/*
+ * void (*set_ldisc)(struct tty_struct *tty);
+ *
+ * 	This routine allows the tty driver to be notified when the
+ * 	device's termios settings have changed.
+ * 
+ */
+
+
+/* This routine is called by the upper-layer tty layer to signal
+   that incoming characters should be throttled because the input
+   buffers are close to full.
+ */
 static void
-cy_close(struct tty_struct * tty, struct file * filp)
+cy_throttle(struct tty_struct * tty)
 {
-  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_close ttyC%d\n", info->line);
+#ifdef SERIAL_DEBUG_THROTTLE
+  char buf[64];
+        
+    printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    if (!info
-    || serial_paranoia_check(info, tty->device, "cy_close")){
-        return;
+    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+            return;
     }
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
-#endif
-
-    save_flags(flags); cli();
 
-    /* If the TTY is being hung up, nothing to do */
-    if (tty_hung_up_p(filp)) {
-	MOD_DEC_USE_COUNT;
-	restore_flags(flags);
-	return;
-    }
-	
-    if ((tty->count == 1) && (info->count != 1)) {
-	/*
-	 * Uh, oh.  tty->count is 1, which means that the tty
-	 * structure will be freed.  Info->count should always
-	 * be one in these conditions.  If it's greater than
-	 * one, we've got real problems, since it means the
-	 * serial port won't be shutdown.
-	 */
-	printk("cy_close: bad serial port count; tty->count is 1, "
-	   "info->count is %d\n", info->count);
-	info->count = 1;
-    }
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
-#endif
-    if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
-	info->count = 0;
+    if (I_IXOFF(tty)) {
+        info->x_char = STOP_CHAR(tty);
+            /* Should use the "Send Special Character" feature!!! */
     }
-    if (info->count)
-    {
-        MOD_DEC_USE_COUNT;
+
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+	save_flags(flags); cli();
+	    base_addr[CyCAR<<index] = (u_char)channel;
+	    base_addr[CyMSVR1<<index] = ~CyRTS;
 	restore_flags(flags);
-	return;
-    }
-    info->flags |= ASYNC_CLOSING;
-    /*
-     * Save the termios structure, since this port may have
-     * separate termios for callout and dialin.
-     */
-    if (info->flags & ASYNC_NORMAL_ACTIVE)
-	info->normal_termios = *tty->termios;
-    if (info->flags & ASYNC_CALLOUT_ACTIVE)
-	info->callout_termios = *tty->termios;
-    if (info->flags & ASYNC_INITIALIZED)
-	tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
-    shutdown(info);
-    if (tty->driver.flush_buffer)
-	tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-	tty->ldisc.flush_buffer(tty);
-    info->event = 0;
-    info->tty = 0;
-    if (info->blocked_open) {
-	if (info->close_delay) {
-	    current->state = TASK_INTERRUPTIBLE;
-	    current->timeout = jiffies + info->close_delay;
-	    schedule();
-	}
-	wake_up_interruptible(&info->open_wait);
+    } else {
+	// Nothing to do!
     }
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-		     ASYNC_CLOSING);
-    wake_up_interruptible(&info->close_wait);
-
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_close done\n");
-#endif
 
-    MOD_DEC_USE_COUNT;
-    restore_flags(flags);
     return;
-} /* cy_close */
-
-/*
- * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void
-cy_hangup(struct tty_struct *tty)
-{
-  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-	
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_hangup ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_hangup"))
-	return;
-    
-    shutdown(info);
-    info->event = 0;
-    info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
-#endif
-    info->tty = 0;
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
-    wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
-
+} /* cy_throttle */
 
 
 /*
- * ------------------------------------------------------------
- * cy_open() and friends
- * ------------------------------------------------------------
+ * This routine notifies the tty driver that it should signal
+ * that characters can now be sent to the tty without fear of
+ * overrunning the input buffers of the line disciplines.
  */
-
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
-                           struct cyclades_port *info)
+static void
+cy_unthrottle(struct tty_struct * tty)
 {
-  struct wait_queue wait = { current, NULL };
-  struct cyclades_card *cinfo;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
-  int chip, channel,index;
-  int retval;
-  char *base_addr;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
 
-    /*
-     * If the device is in the middle of being closed, then block
-     * until it's done, and then try again.
-     */
-    if (info->flags & ASYNC_CLOSING) {
-	interruptible_sleep_on(&info->close_wait);
-	if (info->flags & ASYNC_HUP_NOTIFY){
-	    return -EAGAIN;
-	}else{
-	    return -ERESTARTSYS;
-	}
-    }
+#ifdef SERIAL_DEBUG_THROTTLE
+  char buf[64];
+        
+    printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty), info->line);
+#endif
 
-    /*
-     * If this is a callout device, then just make sure the normal
-     * device isn't being used.
-     */
-    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
-	if (info->flags & ASYNC_NORMAL_ACTIVE){
-	    return -EBUSY;
-	}
-	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-	    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-	    (info->session != current->session)){
-	    return -EBUSY;
-	}
-	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-	    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-	    (info->pgrp != current->pgrp)){
-	    return -EBUSY;
-	}
-	info->flags |= ASYNC_CALLOUT_ACTIVE;
-	return 0;
+    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+            return;
     }
 
-    /*
-     * If non-blocking mode is set, then make the check up front
-     * and then exit.
-     */
-    if (filp->f_flags & O_NONBLOCK) {
-	if (info->flags & ASYNC_CALLOUT_ACTIVE){
-	    return -EBUSY;
-	}
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
+    if (I_IXOFF(tty)) {
+        info->x_char = START_CHAR(tty);
+        /* Should use the "Send Special Character" feature!!! */
     }
 
-    /*
-     * Block waiting for the carrier detect and the line to become
-     * free (i.e., not in use by the callout).  While we are in
-     * this loop, info->count is dropped by one, so that
-     * cy_close() knows when to free things.  We restore it upon
-     * exit, either normal or abnormal.
-     */
-    retval = 0;
-    add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-    printk("block_til_ready before block: ttyC%d, count = %d\n",
-	   info->line, info->count);/**/
-#endif
-    info->count--;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
-    info->blocked_open++;
-
-    cinfo = &cy_card[info->card];
-    channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cinfo->bus_index;
-    base_addr = (char *) (cinfo->base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+	chip = channel>>2;
+	channel &= 0x03;
+	index = cy_card[card].bus_index;
+	base_addr = (unsigned char*)
+		       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
-    while (1) {
-	save_flags(flags); cli();
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
-		base_addr[CyCAR<<index] = (u_char)channel;
-		base_addr[CyMSVR1<<index] = CyRTS;
-		base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-                printk("cyc: %d: raising DTR\n", __LINE__);
-                printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
-#endif
-	    }
-	restore_flags(flags);
-	current->state = TASK_INTERRUPTIBLE;
-	if (tty_hung_up_p(filp)
-	|| !(info->flags & ASYNC_INITIALIZED) ){
-	    if (info->flags & ASYNC_HUP_NOTIFY) {
-		retval = -EAGAIN;
-	    }else{
-		retval = -ERESTARTSYS;
-	    }
-	    break;
-	}
 	save_flags(flags); cli();
 	    base_addr[CyCAR<<index] = (u_char)channel;
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
-	    && !(info->flags & ASYNC_CLOSING)
-	    && (C_CLOCAL(tty)
-	        || (base_addr[CyMSVR1<<index] & CyDCD))) {
-		    restore_flags(flags);
-		    break;
-	    }
+	    base_addr[CyMSVR1<<index] = CyRTS;
 	restore_flags(flags);
-	if (current->signal & ~current->blocked) {
-	    retval = -ERESTARTSYS;
-	    break;
-	}
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready blocking: ttyC%d, count = %d\n",
-	       info->line, info->count);/**/
-#endif
-	schedule();
+    }else{
+	// Nothing to do!
     }
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&info->open_wait, &wait);
-    if (!tty_hung_up_p(filp)){
-	info->count++;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
+
+    return;
+} /* cy_unthrottle */
+
+
+/* cy_start and cy_stop provide software output flow control as a
+   function of XON/XOFF, software CTS, and other such stuff.
+*/
+static void
+cy_stop(struct tty_struct *tty)
+{
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned char *base_addr;
+  int chip,channel,index;
+  unsigned long flags;
+
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_stop ttyC%d\n", info->line); /* */
 #endif
+
+    if (serial_paranoia_check(info, tty->device, "cy_stop"))
+        return;
+        
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+    if (!IS_CYC_Z(*cinfo)) {
+        index = cinfo->bus_index;
+        chip = channel>>2;
+        channel &= 0x03;
+        base_addr = (unsigned char*)
+                   (cy_card[info->card].base_addr
+                           + (cy_chip_offset[chip]<<index));
+
+        save_flags(flags); cli();
+            base_addr[CyCAR<<index] =
+	        (u_char)(channel & 0x0003); /* index channel */
+            base_addr[CySRER<<index] &= ~CyTxMpty;
+        restore_flags(flags);
+    } else {
+	// Nothing to do!
     }
-    info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-    printk("block_til_ready after blocking: ttyC%d, count = %d\n",
-	   info->line, info->count);/**/
-#endif
-    if (retval)
-	    return retval;
-    info->flags |= ASYNC_NORMAL_ACTIVE;
-    return 0;
-} /* block_til_ready */
 
-/*
- * This routine is called whenever a serial port is opened.  It
- * performs the serial-specific initialization for the tty structure.
- */
-int
-cy_open(struct tty_struct *tty, struct file * filp)
+    return;
+} /* cy_stop */
+
+
+static void
+cy_start(struct tty_struct *tty)
 {
-  struct cyclades_port  *info;
-  int retval, line;
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned char *base_addr;
+  int chip,channel,index;
+  unsigned long flags;
 
-    line = MINOR(tty->device) - tty->driver.minor_start;
-    if ((line < 0) || (NR_PORTS <= line)){
-        return -ENODEV;
-    }
-    info = &cy_port[line];
-    if (info->line < 0){
-        return -ENODEV;
-    }
 #ifdef SERIAL_DEBUG_OTHER
-    printk("cy_open ttyC%d\n", info->line); /* */
-#endif
-    if (serial_paranoia_check(info, tty->device, "cy_open")){
-        return -ENODEV;
-    }
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_open ttyC%d, count = %d\n", info->line, info->count);/**/
-#endif
-    info->count++;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
+    printk("cyc:cy_start ttyC%d\n", info->line); /* */
 #endif
-    tty->driver_data = info;
-    info->tty = tty;
 
-    if (!tmp_buf) {
-	tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
-	if (!tmp_buf){
-	    return -ENOMEM;
-        }
+    if (serial_paranoia_check(info, tty->device, "cy_start"))
+        return;
+        
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+    index = cinfo->bus_index;
+    if (!IS_CYC_Z(*cinfo)) {
+        chip = channel>>2;
+        channel &= 0x03;
+        base_addr = (unsigned char*)
+                       (cy_card[info->card].base_addr
+		       + (cy_chip_offset[chip]<<index));
+
+        save_flags(flags); cli();
+            base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
+            base_addr[CySRER<<index] |= CyTxMpty;
+        restore_flags(flags);
+    } else {
+	// Nothing to do!
     }
 
-    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-	if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
-	    *tty->termios = info->normal_termios;
-	else 
-	    *tty->termios = info->callout_termios;
-    }
-    /*
-     * Start up serial port
-     */
-    retval = startup(info);
-    if (retval){
-	return retval;
-    }
+    return;
+} /* cy_start */
 
-    MOD_INC_USE_COUNT;
 
-    retval = block_til_ready(tty, filp, info);
-    if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-	printk("cy_open returning after block_til_ready with %d\n",
-	       retval);
+/*
+ * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void
+cy_hangup(struct tty_struct *tty)
+{
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+        
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
 #endif
-	return retval;
-    }
 
-    info->session = current->session;
-    info->pgrp = current->pgrp;
+    if (serial_paranoia_check(info, tty->device, "cy_hangup"))
+        return;
+    
+    shutdown(info);
+    info->event = 0;
+    info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+#endif
+    info->tty = 0;
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+    wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
 
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_open done\n");/**/
+
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
+                                
+#ifdef SERIAL_DEBUG_IO
+    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
 #endif
-    return 0;
-} /* cy_open */
 
+    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+        return;
+    save_flags(flags); cli();
+        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+    restore_flags(flags);
+    wake_up_interruptible(&tty->write_wait);
+    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+    && tty->ldisc.write_wakeup)
+        (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
 
 
 /*
@@ -2692,21 +3868,11 @@
  * ---------------------------------------------------------------------
  */
 
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static inline void
-show_version(void)
-{
-    printk("Cyclom driver %s\n",rcsid);
-} /* show_version */
 
-/* initialize chips on card -- return number of valid
+/* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
 __initfunc(static int
-cy_init_card(unsigned char *true_base_addr,int index))
+cyy_init_card(unsigned char *true_base_addr,int index))
 {
   unsigned int chip_number;
   unsigned char* base_addr;
@@ -2716,7 +3882,8 @@
     udelay(500L);
 
     for(chip_number=0; chip_number<CyMaxChipsPerCard; chip_number++){
-        base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
+        base_addr = true_base_addr
+	               + (cy_chip_offset[chip_number]<<index);
         udelay(1000L);
         if(base_addr[CyCCR<<index] != 0x00){
             /*************
@@ -2736,39 +3903,396 @@
            and this must be a Cyclom-16Y, not a Cyclom-32Ye.
         */
         if (chip_number == 4
-        && *(true_base_addr + (cy_chip_offset[0]<<index) + (CyGFRCR<<index)) == 0){
-	    return chip_number;
+        && *(true_base_addr
+	    + (cy_chip_offset[0]<<index)
+	    + (CyGFRCR<<index)) == 0){
+            return chip_number;
         }
 
         base_addr[CyCCR<<index] = CyCHIP_RESET;
         udelay(1000L);
 
         if(base_addr[CyGFRCR<<index] == 0x00){
-	    /*
-            printk(" chip #%d at %#6lx is not responding (GFRCR stayed 0)\n",
+            /*
+            printk(" chip #%d at %#6lx is not responding ",
                chip_number, (unsigned long)base_addr);
-	    */
+            printk("(GFRCR stayed 0)\n",
+            */
             return chip_number;
         }
         if((0xf0 & base_addr[CyGFRCR<<index]) != 0x40){
-	    /*
+            /*
             printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
-               chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
-	    */
+               chip_number, (unsigned long)base_addr,
+	       base_addr[CyGFRCR<<index]);
+            */
             return chip_number;
         }
         base_addr[CyGCR<<index] = CyCH0_SERIAL;
-        base_addr[CyPPR<<index] = 244; /* better value than CyCLOCK_25_1MS * 5
-                                                  to run clock at 200 Hz */
+        base_addr[CyPPR<<index] = 244;
+	                       /* better value than CyCLOCK_25_1MS * 5
+					  to run clock at 200 Hz */
 
-	/*
+        /*
         printk(" chip #%d at %#6lx is rev 0x%2x\n",
-               chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
-	*/
+               chip_number, (unsigned long)base_addr,
+	       base_addr[CyGFRCR<<index]);
+        */
     }
 
     return chip_number;
-} /* cy_init_card */
+} /* cyy_init_card */
+
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
+ * sets global variables and return the number of ISA boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_isa(void))
+{
+  unsigned int          cy_isa_irq,nboard;
+  unsigned char         *cy_isa_address;
+  unsigned short        i,j,cy_isa_nchan;
+
+        nboard = 0;
+
+        /* scan the address table probing for Cyclom-Y/ISA boards */
+        for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+                cy_isa_address = cy_isa_addresses[i];
+                if (cy_isa_address  == 0x0000) {
+                        return(nboard);
+                }
+
+                /* probe for CD1400... */
+#if LINUX_VERSION_CODE >= 131328
+		cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000);
+#endif
+                cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0);
+                if (cy_isa_nchan == 0) {
+                        continue;
+                }
+
+                /* find out the board's irq by probing */
+                cy_isa_irq = do_auto_irq(cy_isa_address);
+                if (cy_isa_irq == 0) {
+                        printk("Cyclom-Y/ISA found at 0x%x ",
+                                (unsigned int) cy_isa_address);
+                        printk("but the IRQ could not be detected.\n");
+                        continue;
+                }
+
+                if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
+                        printk("Cyclom-Y/ISA found at 0x%x ",
+                                (unsigned int) cy_isa_address);
+                        printk("but no more channels are available.\n");
+                        return(nboard);
+                }
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                        printk("Cyclom-Y/ISA found at 0x%x ",
+                                (unsigned int) cy_isa_address);
+                        printk("but no more cards can be used .\n");
+                        return(nboard);
+                }
+
+                /* allocate IRQ */
+                if(request_irq(cy_isa_irq, cyy_interrupt,
+				   SA_INTERRUPT, "cyclomY", NULL))
+                {
+                        printk("Cyclom-Y/ISA found at 0x%x ",
+                                (unsigned int) cy_isa_address);
+                        printk("but could not allocate IRQ#%d.\n",
+                                cy_isa_irq);
+                        return(nboard);
+                }
+
+                /* set cy_card */
+                cy_card[j].base_addr = (int) cy_isa_address;
+                cy_card[j].ctl_addr = 0;
+                cy_card[j].irq = (int) cy_isa_irq;
+                cy_card[j].bus_index = 0;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = cy_isa_nchan/4;
+                IRQ_cards[cy_isa_irq] = &cy_card[j];
+                nboard++;
+                        
+                /* print message */
+                printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, ",
+                        j+1, (unsigned int) cy_isa_address,
+                        (unsigned int)(cy_isa_address + 0x1fff),
+			cy_isa_irq);
+                printk("%d channels starting from port %d.\n",
+                        cy_isa_nchan, cy_next_channel);
+                cy_next_channel += cy_isa_nchan;
+        }
+        return(nboard);
+
+} /* cy_detect_isa */
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
+ * sets global variables and return the number of PCI boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_pci(void))
+{
+#ifdef CONFIG_PCI
+  unsigned char         cyy_bus, cyy_dev_fn, cyy_rev_id;
+  unsigned long         pci_intr_ctrl;
+  unsigned char         cy_pci_irq;
+  unsigned int          cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
+  unsigned short        i,j,cy_pci_nchan;
+  unsigned short        device_id,dev_index = 0,board_index = 0;
+
+        if(pcibios_present() == 0) {    /* PCI bus not present */
+                return(0);
+        }
+        for (i = 0; i < NR_CARDS; i++) {
+                /* look for a Cyclades card by vendor and device id */
+                while((device_id = cy_pci_dev_id[dev_index]) != 0) {
+                        if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id,board_index,
+                                        &cyy_bus, &cyy_dev_fn) != 0)
+                        {
+                                dev_index++;    /* try next device id */
+                                board_index = 0;
+                        } else {
+                                board_index++;
+                                break;          /* found a board */
+                        }
+                }
+
+                /* read PCI configuration area */
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                 PCI_INTERRUPT_LINE, &cy_pci_irq);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_0, &cy_pci_addr0);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_1, &cy_pci_addr1);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_2, &cy_pci_addr2);
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                  PCI_REVISION_ID, &cyy_rev_id);
+    if (device_id == 0){
+	break;
+    }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
+	   || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+		cyy_bus, cyy_dev_fn);
+            printk("rev_id=%d) IRQ%d\n",
+		cyy_rev_id, (int)cy_pci_irq);
+            printk("Cyclom-Y/PCI:found  winaddr=0x%x ioaddr=0x%x\n",
+		cy_pci_addr2, cy_pci_addr1);
+#endif
+                cy_pci_addr1  &= 0xfffffffc;
+                cy_pci_addr2  &= 0xfffffff0;
+
+#if LINUX_VERSION_CODE < 131328
+                if ((ulong)cy_pci_addr2 >= 0x100000)  /* above 1M? */
+#endif
+		    cy_pci_addr2 =
+			(unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin);
+
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n",
+		cy_pci_addr2, cy_pci_addr1);
+#endif
+                cy_pci_nchan = 4 * cyy_init_card((unsigned char *)
+                                                cy_pci_addr2,1);
+                if(cy_pci_nchan == 0) {
+                        printk("Cyclom-Y PCI host card with ");
+                        printk("no Serial-Modules at 0x%x.\n",
+			    (unsigned int) cy_pci_addr2);
+                        continue;
+                }
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclom-Y/PCI found at 0x%x ",
+			    (unsigned int) cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        return(i);
+                }
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                        printk("Cyclom-Y/PCI found at 0x%x ",
+			    (unsigned int) cy_pci_addr2);
+                        printk("but no more cards can be used.\n");
+                        return(i);
+                }
+
+                /* allocate IRQ */
+                if(request_irq(cy_pci_irq, cyy_interrupt,
+		        SA_INTERRUPT, "cyclomY", NULL))
+                {
+                        printk("Cyclom-Y/PCI found at 0x%x ",
+			    (unsigned int) cy_pci_addr2);
+                        printk("but could not allocate IRQ%d.\n",
+			    cy_pci_irq);
+                        return(i);
+                }
+
+                /* set cy_card */
+                cy_card[j].base_addr = (int) cy_pci_addr2;
+                cy_card[j].ctl_addr = 0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = cy_pci_nchan/4;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* enable interrupts in the PCI interface */
+                outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
+                pci_intr_ctrl = (unsigned long)
+		                (inw(cy_pci_addr1+0x68)
+				| inw(cy_pci_addr1+0x6a)<<16);
+
+                /* print message */
+                printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+		    j+1, cy_pci_addr2, (cy_pci_addr2 + CyPCI_Ywin - 1),
+		    (int)cy_pci_irq);
+                printk("%d channels starting from port %d.\n",
+		    cy_pci_nchan, cy_next_channel);
+
+                cy_next_channel += cy_pci_nchan;
+    }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
+	    /* print message */
+		printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+		    cyy_bus, cyy_dev_fn);
+		printk("rev_id=%d) IRQ%d\n",
+		    cyy_rev_id, (int)cy_pci_irq);
+		printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+		    cy_pci_addr2, cy_pci_addr0);
+	    printk("Cyclom-Z/PCI not supported for low addresses\n");
+	    break;
+    }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+		cyy_bus, cyy_dev_fn);
+            printk("rev_id=%d) IRQ%d\n",
+		cyy_rev_id, (int)cy_pci_irq);
+            printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+                cy_pci_addr2, cy_pci_addr0);
+#endif
+                cy_pci_addr2 &= 0xfffffff0;
+                cy_pci_addr2 = (unsigned int) vremap(
+                               cy_pci_addr2 & PAGE_MASK,
+                               PAGE_ALIGN(CyPCI_Zwin))
+                               + (cy_pci_addr2 & (PAGE_SIZE-1));
+                cy_pci_addr0 &= 0xfffffff0;
+                cy_pci_addr0 = (unsigned int) vremap(
+                               cy_pci_addr0 & PAGE_MASK,
+                               PAGE_ALIGN(CyPCI_Zctl))
+                               + (cy_pci_addr0 & (PAGE_SIZE-1));
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
+                cy_pci_addr2, cy_pci_addr0);
+	    ((struct RUNTIME_9060 *)(cy_pci_addr0))
+					    ->loc_addr_base = WIN_CREG;
+            PAUSE
+            printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n",
+		0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id,
+		0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version);
+	    ((struct RUNTIME_9060 *)(cy_pci_addr0))
+					    ->loc_addr_base = WIN_RAM;
+#endif
+	    /* The following clears the firmware id word.  This ensures
+	       that the driver will not attempt to talk to the board
+	       until it has been properly initialized.
+	     */
+		PAUSE
+		*(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L;
+
+                /* This must be a Cyclom-8Zo/PCI.  The extendable
+                   version will have a different device_id and will
+                   be allocated its maximum number of ports. */
+                cy_pci_nchan = 8;
+
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+		    printk("Cyclom-Z/PCI found at 0x%x ",
+			(unsigned int) cy_pci_addr2);
+		    printk("but no more cards can be used.\n");
+		    return(i);
+                }
+
+                /* allocate IRQ only if board has an IRQ */
+		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+		    if(request_irq(cy_pci_irq,cyz_interrupt,
+			SA_INTERRUPT,"cyclomZ",NULL))
+		    {
+			printk("Could not allocate IRQ%d ",
+			    (unsigned int) cy_pci_addr2);
+			printk("for Cyclom-Z/PCI at 0x%x.\n",
+			    cy_pci_irq);
+			return(i);
+		    }
+		}
+
+                /* set cy_card */
+                cy_card[j].base_addr = cy_pci_addr2;
+                cy_card[j].ctl_addr = cy_pci_addr0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = 1;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* print message */
+		/* don't report IRQ if board is no IRQ */
+		if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+		    printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+			j+1,cy_pci_addr2,
+			(cy_pci_addr2 + CyPCI_Zwin - 1),
+			(int)cy_pci_irq);
+		}else{
+		    printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ",
+			j+1,cy_pci_addr2,
+			(cy_pci_addr2 + CyPCI_Zwin - 1));
+		}
+                printk("%d channels starting from port %d.\n",
+		    cy_pci_nchan,cy_next_channel);
+                cy_next_channel += cy_pci_nchan;
+    }
+        }
+        return(i);
+#else
+        return(0);
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
+
+
+/*
+ * This routine prints out the appropriate serial driver version number
+ * and identifies which options were configured into this driver.
+ */
+static inline void
+show_version(void)
+{
+  char *rcsvers, *rcsdate, *tmp;
+    rcsvers = strchr(rcsid, ' '); rcsvers++;
+    tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
+    rcsdate = strchr(tmp, ' '); rcsdate++;
+    tmp = strrchr(rcsdate, ' '); *tmp = '\0';
+    printk("Cyclom driver %s %s\n",
+        rcsvers, rcsdate);
+    printk("\tbuilt %s %s\n",
+	__DATE__, __TIME__);
+} /* show_version */
+
 
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
@@ -2783,15 +4307,18 @@
     device driver because the Cyclom is more properly a multiplexer,
     not just an aggregation of serial ports on one card.
 
-    If there are more cards with more ports than have been statically
-    allocated above, a warning is printed and the extra ports are ignored.
+    If there are more cards with more ports than have been
+    statically allocated above, a warning is printed and the
+    extra ports are ignored.
  */
+
 __initfunc(int
 cy_init(void))
 {
-  struct cyclades_port	*info;
+  struct cyclades_port  *info;
   struct cyclades_card *cinfo;
-  int			board,port,i;
+  int number_z_boards = 0;
+  int board,port,i;
 
     show_version();
 
@@ -2807,7 +4334,7 @@
     cy_serial_driver.subtype = SERIAL_TYPE_NORMAL;
     cy_serial_driver.init_termios = tty_std_termios;
     cy_serial_driver.init_termios.c_cflag =
-	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+            B9600 | CS8 | CREAD | HUPCL | CLOCAL;
     cy_serial_driver.flags = TTY_DRIVER_REAL_RAW;
     cy_serial_driver.refcount = &serial_refcount;
     cy_serial_driver.table = serial_table;
@@ -2839,27 +4366,27 @@
     cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
     if (tty_register_driver(&cy_serial_driver))
-	    panic("Couldn't register Cyclom serial driver\n");
+            panic("Couldn't register Cyclom serial driver\n");
     if (tty_register_driver(&cy_callout_driver))
-	    panic("Couldn't register Cyclom callout driver\n");
+            panic("Couldn't register Cyclom callout driver\n");
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
     for (i = 0; i < 16; i++) {
-	    IRQ_cards[i] = 0;
+            IRQ_cards[i] = 0;
     }
 
     for (i = 0; i < NR_CARDS; i++) {
-	    /* base_addr=0 indicates board not found */
-	    cy_card[i].base_addr = 0;
+            /* base_addr=0 indicates board not found */
+            cy_card[i].base_addr = 0;
     }
 
     /* the code below is responsible to find the boards. Each different
        type of board has its own detection routine. If a board is found,
        the next cy_card structure available is set by the detection
-       routine. These functions are responsible for checking the availability
-       of cy_card and cy_port data structures and updating the
-       cy_next_channel. */
+       routine. These functions are responsible for checking the
+       availability of cy_card and cy_port data structures and updating
+       the cy_next_channel. */
 
     /* look for isa boards */
     cy_isa_nboard = cy_detect_isa();
@@ -2871,289 +4398,195 @@
 
     /* invalidate remaining cy_card structures */
     for (i = 0 ; i < NR_CARDS ; i++) {
-	if (cy_card[i].base_addr == 0) {
-		cy_card[i].first_line = -1;
-	}
+        if (cy_card[i].base_addr == 0) {
+                cy_card[i].first_line = -1;
+                cy_card[i].ctl_addr = 0;
+                cy_card[i].irq = 0;
+                cy_card[i].bus_index = 0;
+                cy_card[i].first_line = 0;
+                cy_card[i].num_chips = 0;
+        }
     }
     /* invalidate remaining cy_port structures */
     for (i = cy_next_channel ; i < NR_PORTS ; i++) {
-	cy_port[i].line = -1;
-	cy_port[i].magic = -1;
+        cy_port[i].line = -1;
+        cy_port[i].magic = -1;
     }
 
     /* initialize per-port data structures for each valid board found */
     for (board = 0 ; board < cy_nboard ; board++) {
-	    cinfo = &cy_card[board];
-	    for (port = cinfo->first_line ;
-		 port < cinfo->first_line + 4*cinfo->num_chips ;
-		 port++)
-	    {
-		info = &cy_port[port];
-		info->magic = CYCLADES_MAGIC;
-		info->type = PORT_CIRRUS;
-		info->card = board;
-		info->line = port;
-		info->flags = STD_COM_FLAGS;
-		info->tty = 0;
-		info->xmit_fifo_size = 12;
-		info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
-		info->cor2 = CyETC;
-		info->cor3 = 0x08; /* _very_ small receive threshold */
-		info->cor4 = 0;
-		info->cor5 = 0;
-		info->tbpr = baud_bpr[13]; /* Tx BPR */
-		info->tco = baud_co[13]; /* Tx CO */
-		info->rbpr = baud_bpr[13]; /* Rx BPR */
-		info->rco = baud_co[13]; /* Rx CO */
-		info->close_delay = 0;
-		info->x_char = 0;
-		info->event = 0;
-		info->count = 0;
+            cinfo = &cy_card[board];
+            if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */
+		number_z_boards++;
+                for (port = cinfo->first_line ;
+                     port < cinfo->first_line + 8;
+                     port++)
+                {
+                    info = &cy_port[port];
+                    info->magic = CYCLADES_MAGIC;
+                    info->type = PORT_STARTECH;
+                    info->card = board;
+                    info->line = port;
+                    info->flags = STD_COM_FLAGS;
+                    info->tty = 0;
+                    info->xmit_fifo_size = 0;
+                    info->cor1 = 0;
+                    info->cor2 = 0;
+                    info->cor3 = 0;
+                    info->cor4 = 0;
+                    info->cor5 = 0;
+                    info->tbpr = 0;
+                    info->tco = 0;
+                    info->rbpr = 0;
+                    info->rco = 0;
+                    info->close_delay = 0;
+                    info->x_char = 0;
+                    info->event = 0;
+                    info->count = 0;
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: setting count to 0\n", __LINE__);
+        printk("cyc:cy_init(1) setting Z count to 0\n");
+#endif
+                    info->blocked_open = 0;
+                    info->default_threshold = 0;
+                    info->default_timeout = 0;
+                    info->tqueue.routine = do_softint;
+                    info->tqueue.data = info;
+                    info->callout_termios =
+		                cy_callout_driver.init_termios;
+                    info->normal_termios =
+		                cy_serial_driver.init_termios;
+                    info->open_wait = 0;
+                    info->close_wait = 0;
+                    /* info->session */
+                    /* info->pgrp */
+                    info->read_status_mask = 0;
+                    /* info->timeout */
+		    /* Bentson's vars */
+                    info->jiffies[0] = 0;
+                    info->jiffies[1] = 0;
+                    info->jiffies[2] = 0;
+                    info->rflush_count = 0;
+                }
+                continue;
+            }else{ /* Cyclom-Y of some kind*/
+                for (port = cinfo->first_line ;
+                     port < cinfo->first_line + 4*cinfo->num_chips ;
+                     port++)
+                {
+                    info = &cy_port[port];
+                    info->magic = CYCLADES_MAGIC;
+                    info->type = PORT_CIRRUS;
+                    info->card = board;
+                    info->line = port;
+                    info->flags = STD_COM_FLAGS;
+                    info->tty = 0;
+                    info->xmit_fifo_size = 12;
+                    info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
+                    info->cor2 = CyETC;
+                    info->cor3 = 0x08; /* _very_ small rcv threshold */
+                    info->cor4 = 0;
+                    info->cor5 = 0;
+                    info->tbpr = baud_bpr[13]; /* Tx BPR */
+                    info->tco = baud_co[13]; /* Tx CO */
+                    info->rbpr = baud_bpr[13]; /* Rx BPR */
+                    info->rco = baud_co[13]; /* Rx CO */
+                    info->close_delay = 0;
+                    info->x_char = 0;
+                    info->event = 0;
+                    info->count = 0;
+#ifdef SERIAL_DEBUG_COUNT
+        printk("cyc:cy_init(2) setting Y count to 0\n");
+#endif
+                    info->blocked_open = 0;
+                    info->default_threshold = 0;
+                    info->default_timeout = 0;
+                    info->tqueue.routine = do_softint;
+                    info->tqueue.data = info;
+                    info->callout_termios =
+		               cy_callout_driver.init_termios;
+                    info->normal_termios =
+		               cy_serial_driver.init_termios;
+                    info->open_wait = 0;
+                    info->close_wait = 0;
+                    /* info->session */
+                    /* info->pgrp */
+                    info->read_status_mask =
+		                  CyTIMEOUT| CySPECHAR| CyBREAK
+                                  | CyPARITY| CyFRAME| CyOVERRUN;
+                    /* info->timeout */
+                }
+            }
+    }
+    
+    if ( number_z_boards && !cyz_timeron){
+        cyz_timeron++;
+	cyz_timerlist.expires = jiffies + 1;
+	add_timer(&cyz_timerlist);
+#ifdef CY_PCI_DEBUG
+	printk("Cyclom-Z polling initialized\n");
 #endif
-		info->blocked_open = 0;
-		info->default_threshold = 0;
-		info->default_timeout = 0;
-		info->tqueue.routine = do_softint;
-		info->tqueue.data = info;
-		info->callout_termios =cy_callout_driver.init_termios;
-		info->normal_termios = cy_serial_driver.init_termios;
-		info->open_wait = 0;
-		info->close_wait = 0;
-		/* info->session */
-		/* info->pgrp */
-		info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK
-                                       | CyPARITY| CyFRAME| CyOVERRUN;
-		/* info->timeout */
-	    }
     }
+
     return 0;
     
 } /* cy_init */
 
 #ifdef MODULE
+/* See linux/drivers/char/riscom.c for ideas on how to
+   pass additional base addresses to the driver!!! */
 int
 init_module(void)
 {
    return(cy_init());
-}
+} /* init_module */
 
 void
 cleanup_module(void)
 {
-    unsigned long flags;
     int i;
+    unsigned long flags;
+
+
+    if (cyz_timeron){
+	cyz_timeron = 0;
+	del_timer(&cyz_timerlist);
+    }
 
     save_flags(flags);
     cli();
-    remove_bh(CYCLADES_BH); 
+    remove_bh(CYCLADES_BH);
     if (tty_unregister_driver(&cy_callout_driver))
-	    printk("Couldn't unregister Cyclom callout driver\n");
+            printk("Couldn't unregister Cyclom callout driver\n");
     if (tty_unregister_driver(&cy_serial_driver))
-	    printk("Couldn't unregister Cyclom serial driver\n");
+            printk("Couldn't unregister Cyclom serial driver\n");
     restore_flags(flags);
 
     for (i = 0; i < NR_CARDS; i++) {
-        if (cy_card[i].base_addr != 0)
-	{
-	    free_irq(cy_card[i].irq,NULL);
-	}
+        if (cy_card[i].base_addr != 0
+	    && cy_card[i].irq)
+        {
+            free_irq(cy_card[i].irq,NULL);
+        }
     }
-}
-#endif
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
- * sets global variables and return the number of ISA boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_isa())
-{
-  unsigned int		cy_isa_irq,nboard;
-  unsigned char		*cy_isa_address;
-  unsigned short	i,j,cy_isa_nchan;
-
-	nboard = 0;
-
-	/* scan the address table probing for Cyclom-Y/ISA boards */
-	for (i = 0 ; i < NR_ISA_ADDRESSES ; i++) {
-		cy_isa_address = cy_isa_addresses[i];
-		if (cy_isa_address  == 0x0000) {
-			return(nboard);
-		}
-
-		/* probe for CD1400... */
-		cy_isa_nchan = 4 * cy_init_card(cy_isa_address,0);
-		if (cy_isa_nchan == 0) {
-			continue;
-		}
-
-		/* find out the board's irq by probing */
-		cy_isa_irq = do_auto_irq(cy_isa_address);
-		if (cy_isa_irq == 0) {
-			printk("Cyclom-Y/ISA found at 0x%x but the IRQ could not be detected.\n",
-				(unsigned int) cy_isa_address);
-			continue;
-		}
-
-		if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
-			printk("Cyclom-Y/ISA found at 0x%x but no more channel structures are available.\n",
-				(unsigned int) cy_isa_address);
-			return(nboard);
-		}
-		/* fill the next cy_card structure available */
-		for (j = 0 ; j < NR_CARDS ; j++) {
-			if (cy_card[j].base_addr == 0)	break;
-		}
-		if (j == NR_CARDS) {	/* no more cy_cards available */
-			printk("Cyclom-Y/ISA found at 0x%x but no more card structures are available.\n",
-				(unsigned int) cy_isa_address);
-			return(nboard);
-		}
-
-		/* allocate IRQ */
-		if(request_irq(cy_isa_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
-		{
-			printk("Cyclom-Y/ISA found at 0x%x but could not allocate interrupt IRQ#%d.\n",
-				(unsigned int) cy_isa_address,cy_isa_irq);
-			return(nboard);
-		}
-
-		/* set cy_card */
-		cy_card[j].base_addr = (int) cy_isa_address;
-		cy_card[j].irq = (int) cy_isa_irq;
-		cy_card[j].bus_index = 0;
-		cy_card[j].first_line = cy_next_channel;
-		cy_card[j].num_chips = cy_isa_nchan/4;
-	        IRQ_cards[cy_isa_irq] = &cy_card[j];
-		nboard++;
-			
-		/* print message */
-		printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
-			j+1,(unsigned int) cy_isa_address,
-			(unsigned int)(cy_isa_address + 0x1fff),
-			cy_isa_irq,cy_isa_nchan,cy_next_channel);
-		cy_next_channel += cy_isa_nchan;
-	}
-	return(nboard);
-
-}
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-__initfunc(int
-cy_detect_pci())
+} /* cleanup_module */
+#else
+/* called by linux/init/main.c to parse command line options */
+void
+cy_setup(char *str, int *ints)
 {
-#ifdef CONFIG_PCI
-  unsigned char		cyy_bus, cyy_dev_fn, cyy_rev_id;
-  unsigned long		pci_intr_ctrl;
-  unsigned char		cy_pci_irq;
-  unsigned int		cy_pci_address, cy_pci_io;
-  unsigned short	i,j,cy_pci_nchan;
-  unsigned short	device_id,dev_index = 0,board_index = 0;
-
-	if(pcibios_present() == 0) {	/* PCI bus not present */
-	 	return(0);
-	}
-	for (i = 0; i < NR_CARDS; i++) {
-		/* look for a Cyclom-Y card by vendor and device id */
-		while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-			if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
-					device_id,board_index,
-  					&cyy_bus, &cyy_dev_fn) != 0)
-			{
-				dev_index++;	/* try next device id */
-				board_index = 0;
-			} else {
-				board_index++;
-				break;		/* found a board */
-			}
-  		}
-		if (device_id == 0)	break;
-
-		/* read PCI configuration area */
-		pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
-				 PCI_INTERRUPT_LINE, &cy_pci_irq);
-		pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
-				  PCI_BASE_ADDRESS_1, &cy_pci_io);
-		pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
-				  PCI_BASE_ADDRESS_2, &cy_pci_address);
-		pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
-				  PCI_REVISION_ID, &cyy_rev_id);
-		cy_pci_address &= 0xfffffff0;
-		if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */
-			cy_pci_address =
-			    (unsigned int) ioremap(cy_pci_address,0x4000);
-		}
-		cy_pci_io  &= 0xfffffffc;
-		cy_pci_nchan = 4 * cy_init_card((unsigned char *)
-						cy_pci_address,1);
-		if(cy_pci_nchan == 0) {
-			printk("Cyclom-Y PCI host card with no Serial-Modules at 0x%x.\n",
-				(unsigned int) cy_pci_address);
-			continue;
-		}
-		if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
-			printk("Cyclom-Y/PCI found at 0x%x but no more channel structures are available.\n",
-				(unsigned int) cy_pci_address);
-			return(i);
-		}
-#ifdef CY_PCI_DEBUG
-		printk("Cyclom-Ye/PCI #%d (bus=0x0%x, pci_id=0x%x, rev_id=%d).\n",
-			i+1,cyy_bus,cyy_dev_fn,cyy_rev_id);
-		printk("Cyclom-Ye/PCI: found at 0x%x, IRQ%d, ioaddr = 0x%lx.\n",
-			cy_pci_address,(int)cy_pci_irq,cy_pci_io);
-#endif
-		/* fill the next cy_card structure available */
-		for (j = 0 ; j < NR_CARDS ; j++) {
-			if (cy_card[j].base_addr == 0)	break;
-		}
-		if (j == NR_CARDS) {	/* no more cy_cards available */
-			printk("Cyclom-Y/PCI found at 0x%x but no more card structures are available.\n",
-				(unsigned int) cy_pci_address);
-			return(i);
-		}
-
-		/* allocate IRQ */
-		if(request_irq(cy_pci_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
-		{
-			printk("Cyclom-Y/PCI found at 0x%x but could not allocate interrupt IRQ%d.\n",
-				(unsigned int) cy_pci_address,cy_pci_irq);
-			return(i);
-		}
+  int i, j;
 
-		/* set cy_card */
-		cy_card[j].base_addr = (int) cy_pci_address;
-		cy_card[j].irq = (int) cy_pci_irq;
-		cy_card[j].bus_index = 1;
-		cy_card[j].first_line = cy_next_channel;
-		cy_card[j].num_chips = cy_pci_nchan/4;
-	        IRQ_cards[cy_pci_irq] = &cy_card[j];
-
-		/* enable interrupts in the PCI interface */
-		outw(inw(cy_pci_io+0x68)|0x0900,cy_pci_io+0x68);
-		pci_intr_ctrl = (unsigned long)(inw(cy_pci_io+0x68) | inw(cy_pci_io+0x6a)<<16);
-
-		/* print message */
-		printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
-			j+1,(unsigned int) cy_pci_address,
-			(unsigned int)(cy_pci_address + 0x3fff),
-			(int)cy_pci_irq,cy_pci_nchan,cy_next_channel);
+    for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+        if (cy_isa_addresses[i] == 0) break;
+    }
+    for (j = 1; j <= ints[0]; j++){
+        if ( i < NR_ISA_ADDRS ){
+            cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
+        }
+    }
 
-		cy_next_channel += cy_pci_nchan;
-	}
-	return(i);
-#else
-	return(0);
-#endif /* ifdef CONFIG_PCI */
-}
+} /* cy_setup */
+#endif
 
 
 #ifdef CYCLOM_SHOW_STATUS
@@ -3181,7 +4614,8 @@
     printk(" cy_port\n");
     printk("  card line flags = %d %d %x\n",
                  info->card, info->line, info->flags);
-    printk("  *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
+    printk("  *tty read_status_mask timeout xmit_fifo_size ",
+    printk("= %lx %x %x %x\n",
                  (long)info->tty, info->read_status_mask,
                  info->timeout, info->xmit_fifo_size);
     printk("  cor1,cor2,cor3,cor4,cor5 = %x %x %x %x %x\n",
@@ -3198,59 +4632,60 @@
 
     save_flags(flags); cli();
 
-	base_addr = (unsigned char*)
-		       (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+        base_addr = (unsigned char*)
+                       (cy_card[card].base_addr
+		       + (cy_chip_offset[chip]<<index));
 
 /* Global Registers */
 
-	printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
-	printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
-	printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
-	printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
-	printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
-	printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
-	printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
-	printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
-	printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
-	printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
-	printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
+        printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
+        printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
+        printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
+        printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
+        printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
+        printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
+        printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
+        printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
+        printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
+        printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
+        printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
 
-	base_addr[CyCAR<<index] = (u_char)channel;
+        base_addr[CyCAR<<index] = (u_char)channel;
 
 /* Virtual Registers */
 
-	printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
-	printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
-	printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
-	printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
+        printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
+        printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
+        printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
+        printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
 
 /* Channel Registers */
 
-	printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
-	printk(" CySRER %x\n", base_addr[CySRER<<index]);
-	printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
-	printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
-	printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
-	printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
-	printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
-	printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
-	printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
-	printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
-	printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
-	printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
-	printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
-	printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
-	printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
-	printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
-	printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
-	printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
-	printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
-	printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
-	printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
-	printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
-	printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
-	printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
-	printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
+        printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
+        printk(" CySRER %x\n", base_addr[CySRER<<index]);
+        printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
+        printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
+        printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
+        printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
+        printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
+        printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
+        printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
+        printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
+        printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
+        printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
+        printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
+        printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
+        printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
+        printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
+        printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
+        printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
+        printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
+        printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
+        printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
+        printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
+        printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
+        printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
+        printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
 
     restore_flags(flags);
 } /* show_status */
diff -u --recursive --new-file v2.1.36/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.1.36/linux/drivers/char/dsp56k.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/dsp56k.c	Mon May 12 10:35:39 1997
@@ -34,6 +34,7 @@
 #include <linux/delay.h>	/* guess what */
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 
 #include <asm/segment.h>
 #include <asm/atarihw.h>
@@ -529,582 +530,7 @@
 
 static int init_error = 0;
 
-void dsp56k_init(void)
-{
-	if(!ATARIHW_PRESENT(DSP56K)) {
-		init_error = 1;
-		printk("DSP56k driver: Hardware not present\n");
-		return;
-	}
-
-#ifndef MODULE
-	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
-		printk("DSP56k driver: Unable to register driver\n");
-		return;
-	}
-#endif /* !MODULE */
-
-	dsp56k.in_use = 0;
-
-	printk("DSP56k driver installed\n");
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	int r;
-
-	init_error = 0;
-	dsp56k_init();
-	if(init_error)
-		return -EPERM;
-
-	r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops);
-	if(r) {
-		printk("DSP56k driver: Unable to register driver\n");
-		return r;
-	}
-	
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
-}
-#endif /* MODULE */
-/*
- * The DSP56001 Device Driver, saviour of the Free World(tm)
- *
- * Authors: Fredrik Noring   <noring@lysator.liu.se>
- *          lars brinkhoff   <f93labr@dd.chalmers.se>
- *          Tomas Berndtsson <tobe@lysator.liu.se>
- *
- * First version May 1996
- *
- * History:
- *  97-01-29   Tomas Berndtsson,
- *               Integrated with Linux 2.1.21 kernel sources.
- *  97-02-15   Tomas Berndtsson,
- *               Fixed for kernel 2.1.26
- *
- * BUGS:
- *  Hmm... there must be something here :)
- *
- * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/malloc.h>	/* for kmalloc() and kfree() */
-#include <linux/sched.h>	/* for struct wait_queue etc */
-#include <linux/major.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/delay.h>	/* guess what */
-#include <linux/fs.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/atarihw.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h>	/* For put_user and get_user */
-
-#include <asm/dsp56k.h>
-
-/* minor devices */
-#define DSP56K_DEV_56001        0    /* The only device so far */
-
-#define TIMEOUT    10   /* Host port timeout in number of tries */
-#define MAXIO    2048   /* Maximum number of words before sleep */
-#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
-
-#define DSP56K_TX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
-#define DSP56K_TX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
-#define DSP56K_RX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
-
-#define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
-#define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
-
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
-#define wait_some(n) \
-{ \
-	current->state = TASK_INTERRUPTIBLE; \
-	current->timeout = jiffies + n; \
-	schedule(); \
-}
-
-#define handshake(count, maxio, timeout, ENABLE, f) \
-{ \
-	long i, t, m; \
-	while (count > 0) { \
-		m = min(count, maxio); \
-		for (i = 0; i < m; i++) { \
-			for (t = 0; t < timeout && !ENABLE; t++) \
-				wait_some(2); \
-			if(!ENABLE) \
-				return -EIO; \
-			f; \
-		} \
-		count -= m; \
-		if (m == maxio) wait_some(2); \
-	} \
-}
-
-#define tx_wait(n) \
-{ \
-	int t; \
-	for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
-		wait_some(1); \
-	if(!DSP56K_TRANSMIT) { \
-		return -EIO; \
-	} \
-}
-
-#define rx_wait(n) \
-{ \
-	int t; \
-	for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
-		wait_some(1); \
-	if(!DSP56K_RECEIVE) { \
-		return -EIO; \
-	} \
-}
-
-/* DSP56001 bootstrap code */
-static char bootstrap[] = {
-	0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
-	0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
-	0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
-	0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
-	0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
-	0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
-	0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
-	0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
-	0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
-	0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
-	0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
-	0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
-	0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
-	0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
-	0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
-	0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
-	0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
-	0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
-	0xf0, 0x80, 0x00, 0x7e, 0xad};
-static int sizeof_bootstrap = 375;
-
-
-static struct dsp56k_device {
-	int in_use;
-	long maxio, timeout;
-	int tx_wsize, rx_wsize;
-} dsp56k;
-
-static int dsp56k_reset(void)
-{
-	u_char status;
-	
-	/* Power down the DSP */
-	sound_ym.rd_data_reg_sel = 14;
-	status = sound_ym.rd_data_reg_sel & 0xef;
-	sound_ym.wd_data = status;
-	sound_ym.wd_data = status | 0x10;
-  
-	udelay(10);
-  
-	/* Power up the DSP */
-	sound_ym.rd_data_reg_sel = 14;
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
-
-	return 0;
-}
-
-static int dsp56k_upload(u_char *bin, int len)
-{
-	int i;
-	u_char *p;
-	
-	dsp56k_reset();
-  
-	p = bootstrap;
-	for (i = 0; i < sizeof_bootstrap/3; i++) {
-		/* tx_wait(10); */
-		dsp56k_host_interface.data.b[1] = *p++;
-		dsp56k_host_interface.data.b[2] = *p++;
-		dsp56k_host_interface.data.b[3] = *p++;
-	}
-	for (; i < 512; i++) {
-		/* tx_wait(10); */
-		dsp56k_host_interface.data.b[1] = 0;
-		dsp56k_host_interface.data.b[2] = 0;
-		dsp56k_host_interface.data.b[3] = 0;
-	}
-  
-	for (i = 0; i < len; i++) {
-		tx_wait(10);
-		get_user(dsp56k_host_interface.data.b[1], bin++);
-		get_user(dsp56k_host_interface.data.b[2], bin++);
-		get_user(dsp56k_host_interface.data.b[3], bin++);
-	}
-
-	tx_wait(10);
-	dsp56k_host_interface.data.l = 3;    /* Magic execute */
-
-	return 0;
-}
-
-static long dsp56k_read(struct inode *inode, struct file *file,
-			char *buf, unsigned long count)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-	{
-
-		long n;
-
-		/* Don't do anything if nothing is to be done */
-		if (!count) return 0;
-
-		n = 0;
-		switch (dsp56k.rx_wsize) {
-		case 1:  /* 8 bit */
-		{
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
-				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
-			return n;
-		}
-		case 2:  /* 16 bit */
-		{
-			short *data;
-
-			count /= 2;
-			data = (short*) buf;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
-				  put_user(dsp56k_host_interface.data.w[1], data+n++));
-			return 2*n;
-		}
-		case 3:  /* 24 bit */
-		{
-			count /= 3;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
-				  put_user(dsp56k_host_interface.data.b[1], buf+n++);
-				  put_user(dsp56k_host_interface.data.b[2], buf+n++);
-				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
-			return 3*n;
-		}
-		case 4:  /* 32 bit */
-		{
-			long *data;
-
-			count /= 4;
-			data = (long*) buf;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
-				  put_user(dsp56k_host_interface.data.l, data+n++));
-			return 4*n;
-		}
-		}
-		return -EFAULT;
-	}
-
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
-	}
-}
-
-static long dsp56k_write(struct inode *inode, struct file *file,
-			 const char *buf, unsigned long count)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-	{
-		long n;
-
-		/* Don't do anything if nothing is to be done */
-		if (!count) return 0;
-
-		n = 0;
-		switch (dsp56k.tx_wsize) {
-		case 1:  /* 8 bit */
-		{
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
-				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
-			return n;
-		}
-		case 2:  /* 16 bit */
-		{
-			short *data;
-
-			count /= 2;
-			data = (short*) buf;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
-				  get_user(dsp56k_host_interface.data.w[1], data+n++));
-			return 2*n;
-		}
-		case 3:  /* 24 bit */
-		{
-			count /= 3;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
-				  get_user(dsp56k_host_interface.data.b[1], buf+n++);
-				  get_user(dsp56k_host_interface.data.b[2], buf+n++);
-				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
-			return 3*n;
-		}
-		case 4:  /* 32 bit */
-		{
-			long *data;
-
-			count /= 4;
-			data = (long*) buf;
-			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
-				  get_user(dsp56k_host_interface.data.l, data+n++));
-			return 4*n;
-		}
-		}
-
-		return -EFAULT;
-	}
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
-	}
-}
-
-static int dsp56k_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-
-		switch(cmd) {
-		case DSP56K_UPLOAD:
-		{
-			char *bin;
-			int r, len;
-			struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
-    
-			if(get_user(len, &binary->len) < 0)
-				return -EFAULT;
-			if(get_user(bin, &binary->bin) < 0)
-				return -EFAULT;
-		
-			if (len == 0) {
-				return -EINVAL;      /* nothing to upload?!? */
-			}
-			if (len > DSP56K_MAX_BINARY_LENGTH) {
-				return -EINVAL;
-			}
-    
-			r = dsp56k_upload(bin, len);
-			if (r < 0) {
-				return r;
-			}
-    
-			break;
-		}
-		case DSP56K_SET_TX_WSIZE:
-			if (arg > 4 || arg < 1)
-				return -EINVAL;
-			dsp56k.tx_wsize = (int) arg;
-			break;
-		case DSP56K_SET_RX_WSIZE:
-			if (arg > 4 || arg < 1)
-				return -EINVAL;
-			dsp56k.rx_wsize = (int) arg;
-			break;
-		case DSP56K_HOST_FLAGS:
-		{
-			int dir, out, status;
-			struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
-    
-			if(get_user(dir, &hf->dir) < 0)
-				return -EFAULT;
-			if(get_user(out, &hf->out) < 0)
-				return -EFAULT;
-
-			if ((dir & 0x1) && (out & 0x1))
-				dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
-			else if (dir & 0x1)
-				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
-			if ((dir & 0x2) && (out & 0x2))
-				dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
-			else if (dir & 0x2)
-				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
-			status = 0;
-			if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
-			if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
-			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
-			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
-
-			if(put_user(status, &hf->status) < 0)
-				return -EFAULT;
-			break;
-		}
-		case DSP56K_HOST_CMD:
-			if (arg > 31 || arg < 0)
-				return -EINVAL;
-			dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
-							     DSP56K_CVR_HC);
-			break;
-		default:
-			return -EINVAL;
-		}
-		return 0;
-
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
-	}
-}
-
-/* As of 2.1.26 this should be dsp56k_poll,
- * but how do I then check device minor number?
- * Do I need this function at all???
- */
-#ifdef 0
-static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
-			 select_table *wait)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-
-		switch(sel_type) {
-		case SEL_IN:		/* read */
-			return 1;
-		case SEL_OUT:		/* write */
-			return 1;
-		default:
-			return 1;
-		}
-
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
-	}
-}
-#endif
-
-static int dsp56k_open(struct inode *inode, struct file *file)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-
-		if (dsp56k.in_use)
-			return -EBUSY;
-
-		dsp56k.in_use = 1;
-		dsp56k.timeout = TIMEOUT;
-		dsp56k.maxio = MAXIO;
-		dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
-
-		DSP56K_TX_INT_OFF;
-		DSP56K_RX_INT_OFF;
-
-		/* Zero host flags */
-		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
-		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
-
-		break;
-
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
-	}
-
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif /* MODULE */
-
-	return 0;
-}
-
-static void dsp56k_release(struct inode *inode, struct file *file)
-{
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-
-	switch(dev)
-	{
-	case DSP56K_DEV_56001:
-
-		dsp56k.in_use = 0;
-
-		break;
-	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return;
-	}
-
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif /* MODULE */
-}
-
-static struct file_operations dsp56k_fops = {
-	NULL,    /* no special dsp56k_lseek */
-	dsp56k_read,
-	dsp56k_write,
-	NULL,    /* no special dsp56k_readdir */
-	NULL,    /* dsp56k_poll? */
-	dsp56k_ioctl,
-	NULL,    /* no special dsp56k_mmap */
-	dsp56k_open,
-	dsp56k_release,
-	NULL,    /* no special dsp56k_fsync */
-	NULL,    /* no special dsp56k_fasync */
-	NULL,    /* no special dsp56k_check_media_change */
-	NULL     /* no special dsp56k_revalidate */
-};
-
-
-/****** Init and module functions ******/
-
-static int init_error = 0;
-
-void dsp56k_init(void)
+__initfunc(void dsp56k_init(void))
 {
 	if(!ATARIHW_PRESENT(DSP56K)) {
 		init_error = 1;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.1.36/linux/drivers/char/epca.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/epca.c	Mon May 12 10:35:39 1997
@@ -0,0 +1,4313 @@
+/*
+
+ 
+	Copyright (C) 1996  Digi International.
+ 
+	For technical support please email digiLinux@dgii.com or
+	call Digi tech support at (612) 912-3456
+
+	Much of this design and code came from epca.c which was 
+	copyright (C) 1994, 1995 Troy De Jongh, and subsquently 
+	modified by David Nugent, Christoph Lameter, Mike McLagan. 
+ 
+ 	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.
+
+--------------------------------------------------------------------------- */
+/* See README.epca for change history --DAT*/
+
+
+#ifdef MODVERSIONS
+#define MODULE
+#endif
+
+/* -----------------------------------------------------------------------
+   This way modules should work regardless if they defined MODULE or
+   MODVERSIONS.  (MODVERSIONS is for the newer kernels ...
+-------------------------------------------------------------------------- */
+
+#ifdef MODULE
+#include <linux/config.h>
+#endif /* MODULE */
+
+#include <linux/version.h>
+
+#define NEW_MODULES
+
+#ifdef NEW_MODULES
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif /* MODVERSIONS */
+#endif /* NEW_MODULES */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif /* MODULE */
+
+
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+
+#include <asm/bitops.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty_flip.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+
+#ifdef MODULE
+#ifndef NEW_MODULES
+char kernel_version[]=UTS_RELEASE;
+#endif /* NEW_MODULE */ 
+#endif /* MODULE */
+
+
+#ifdef CONFIG_PCI
+#define ENABLE_PCI
+#endif /* CONFIG_PCI */
+
+
+
+#include <asm/uaccess.h>
+#define putUser(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
+#define getUser(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
+
+
+
+#ifdef ENABLE_PCI
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/digiPCI.h>
+#endif /* ENABLE_PCI */
+
+#include <linux/digi1.h>
+#include <linux/digiFep1.h>
+#include <linux/epca.h>
+#include <linux/epcaconfig.h>
+
+/* ---------------------- Begin defines ------------------------ */
+
+#define VERSION            "1.1.0"     
+
+/* This major needs to be submitted to Linux to join the majors list */
+
+#define DIGIINFOMAJOR       35  /* For Digi specific ioctl */ 
+
+
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#define MAXCARDS 7
+#define epcaassert(x, msg)  if (!(x)) epca_error(__LINE__, msg)
+
+/* ----------------- Begin global definitions ------------------- */
+
+static char mesg[100];
+static int pc_refcount, nbdevs = 0, num_cards = 0, liloconfig = 0;
+static int digi_poller_inhibited = 1 ;
+
+static int setup_error_code = 0;
+static int invalid_lilo_config = 0;
+
+/* -----------------------------------------------------------------------
+	MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 
+	7 below.
+--------------------------------------------------------------------------*/
+static struct board_info boards[7];
+
+
+/* ------------- Begin structures used for driver registeration ---------- */
+
+struct tty_driver pc_driver;
+struct tty_driver pc_callout;
+struct tty_driver pc_info;
+
+/* The below structures are used to initialize the tty_driver structures. */
+
+/*	-------------------------------------------------------------------------
+	Note : MAX_ALLOC is currently limited to 0x100.  This restriction is 
+	placed on us by Linux not Digi.
+----------------------------------------------------------------------------*/
+static struct tty_struct *pc_table[MAX_ALLOC];
+static struct termios *pc_termios[MAX_ALLOC];
+static struct termios *pc_termios_locked[MAX_ALLOC];
+
+
+/* ------------------ Begin Digi specific structures -------------------- */
+
+/* ------------------------------------------------------------------------
+	digi_channels represents an array of structures that keep track of
+	each channel of the Digi product.  Information such as transmit and
+	receive pointers, termio data, and signal definitions (DTR, CTS, etc ...)
+	are stored here.  This structure is NOT used to overlay the cards 
+	physical channel structure.
+-------------------------------------------------------------------------- */
+  
+static struct channel digi_channels[MAX_ALLOC];
+
+/* ------------------------------------------------------------------------
+	card_ptr is an array used to hold the address of the
+	first channel structure of each card.  This array will hold
+	the addresses of various channels located in digi_channels.
+-------------------------------------------------------------------------- */
+static struct channel *card_ptr[MAXCARDS];
+
+/* ---------------------- Begin function prototypes --------------------- */
+
+/* ----------------------------------------------------------------------
+	Begin generic memory functions.  These functions will be alias
+	(point at) more specific functions dependant on the board being
+	configured.
+----------------------------------------------------------------------- */
+	
+
+#ifdef MODULE
+int                init_module(void);
+void               cleanup_module(void);
+#endif /* MODULE */
+
+static inline void memwinon(struct board_info *b, unsigned int win);
+static inline void memwinoff(struct board_info *b, unsigned int win);
+static inline void globalwinon(struct channel *ch);
+static inline void rxwinon(struct channel *ch);
+static inline void txwinon(struct channel *ch);
+static inline void memoff(struct channel *ch);
+static inline void assertgwinon(struct channel *ch);
+static inline void assertmemoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for cx_like products --- */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxem_globalwinon(struct channel *ch);
+static inline void pcxem_rxwinon(struct channel *ch);
+static inline void pcxem_txwinon(struct channel *ch);
+static inline void pcxem_memoff(struct channel *ch);
+
+/* ------ Begin more 'specific' memory functions for the pcxe ------- */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxe_globalwinon(struct channel *ch);
+static inline void pcxe_rxwinon(struct channel *ch);
+static inline void pcxe_txwinon(struct channel *ch);
+static inline void pcxe_memoff(struct channel *ch);
+
+/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
+/* Note : pc64xe and pcxi share the same windowing routines */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win);
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win);
+static inline void pcxi_globalwinon(struct channel *ch);
+static inline void pcxi_rxwinon(struct channel *ch);
+static inline void pcxi_txwinon(struct channel *ch);
+static inline void pcxi_memoff(struct channel *ch);
+
+/* - Begin 'specific' do nothing memory functions needed for some cards - */
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win);
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win);
+static inline void dummy_globalwinon(struct channel *ch);
+static inline void dummy_rxwinon(struct channel *ch);
+static inline void dummy_txwinon(struct channel *ch);
+static inline void dummy_memoff(struct channel *ch);
+static inline void dummy_assertgwinon(struct channel *ch);
+static inline void dummy_assertmemoff(struct channel *ch);
+
+/* ------------------- Begin declare functions ----------------------- */
+
+static inline struct channel *verifyChannel(register struct tty_struct *);
+static inline void pc_sched_event(struct channel *, int);
+static void epca_error(int, char *);
+static void pc_close(struct tty_struct *, struct file *);
+static void shutdown(struct channel *);
+static void pc_hangup(struct tty_struct *);
+static void pc_put_char(struct tty_struct *, unsigned char);
+static int pc_write_room(struct tty_struct *);
+static int pc_chars_in_buffer(struct tty_struct *);
+static void pc_flush_buffer(struct tty_struct *);
+static void pc_flush_chars(struct tty_struct *);
+static int block_til_ready(struct tty_struct *, struct file *,
+                           struct channel *);
+static int pc_open(struct tty_struct *, struct file *);
+static void post_fep_init(unsigned int crd);
+static void epcapoll(unsigned long);
+static void doevent(int);
+static void fepcmd(struct channel *, int, int, int, int, int);
+static unsigned termios2digi_h(struct channel *ch, unsigned);
+static unsigned termios2digi_i(struct channel *ch, unsigned);
+static unsigned termios2digi_c(struct channel *ch, unsigned);
+static void epcaparam(struct tty_struct *, struct channel *);
+static void receive_data(struct channel *);
+static int pc_ioctl(struct tty_struct *, struct file *,
+                    unsigned int, unsigned long);
+static void pc_set_termios(struct tty_struct *, struct termios *);
+static void do_softint(void *);
+static void pc_stop(struct tty_struct *);
+static void pc_start(struct tty_struct *);
+static void pc_throttle(struct tty_struct * tty);
+static void pc_unthrottle(struct tty_struct *tty);
+static void digi_send_break(struct channel *ch, int msec);
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
+void epca_setup(char *, int *);
+void console_print(const char *);
+
+static int get_termio(struct tty_struct *, struct termio *);
+static int pc_write(struct tty_struct *, int, const unsigned char *, int);
+int pc_init(void);
+
+#ifdef ENABLE_PCI
+static int init_PCI(int);
+static int get_PCI_configuration(char, char, unsigned int *, unsigned int *,
+                                             unsigned int *, unsigned int *,
+                                             unsigned int *, unsigned int *);
+#endif /* ENABLE_PCI */
+
+
+/* ------------------------------------------------------------------
+	Table of functions for each board to handle memory.  Mantaining 
+	parallelism is a *very* good idea here.  The idea is for the 
+	runtime code to blindly call these functions, not knowing/caring    
+	about the underlying hardware.  This stuff should contain no
+	conditionals; if more functionality is needed a different entry
+	should be established.  These calls are the interface calls and 
+	are the only functions that should be accessed.  Anyone caught
+	making direct calls deserves what they get.
+-------------------------------------------------------------------- */
+
+static inline void memwinon(struct board_info *b, unsigned int win)
+{
+	(b->memwinon)(b, win);
+}
+
+static inline void memwinoff(struct board_info *b, unsigned int win)
+{
+	(b->memwinoff)(b, win);
+}
+
+static inline void globalwinon(struct channel *ch)
+{
+	(ch->board->globalwinon)(ch);
+}
+
+static inline void rxwinon(struct channel *ch)
+{
+	(ch->board->rxwinon)(ch);
+}
+
+static inline void txwinon(struct channel *ch)
+{
+	(ch->board->txwinon)(ch);
+}
+
+static inline void memoff(struct channel *ch)
+{
+	(ch->board->memoff)(ch);
+}
+static inline void assertgwinon(struct channel *ch)
+{
+	(ch->board->assertgwinon)(ch);
+}
+
+static inline void assertmemoff(struct channel *ch)
+{
+	(ch->board->assertmemoff)(ch);
+}
+
+/* ---------------------------------------------------------
+	PCXEM windowing is the same as that used in the PCXR 
+	and CX series cards.
+------------------------------------------------------------ */
+
+static inline void pcxem_memwinon(struct board_info *b, unsigned int win)
+{
+        outb_p(FEPWIN|win, (int)b->port + 1);
+}
+
+static inline void pcxem_memwinoff(struct board_info *b, unsigned int win)
+{
+	outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxem_globalwinon(struct channel *ch)
+{
+	outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_rxwinon(struct channel *ch)
+{
+	outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_txwinon(struct channel *ch)
+{
+	outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxem_memoff(struct channel *ch)
+{
+	outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ----------------- Begin pcxe memory window stuff ------------------ */
+
+static inline void pcxe_memwinon(struct board_info *b, unsigned int win)
+{
+               outb_p(FEPWIN | win, (int)b->port + 1);
+}
+
+static inline void pcxe_memwinoff(struct board_info *b, unsigned int win)
+{
+	outb_p(inb((int)b->port) & ~FEPMEM,
+	           (int)b->port + 1);
+	outb_p(0, (int)b->port + 1);
+}
+
+static inline void pcxe_globalwinon(struct channel *ch)
+{
+	outb_p( FEPWIN, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_rxwinon(struct channel *ch)
+{
+		outb_p(ch->rxwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_txwinon(struct channel *ch)
+{
+		outb_p(ch->txwin, (int)ch->board->port + 1);
+}
+
+static inline void pcxe_memoff(struct channel *ch)
+{
+	outb_p(0, (int)ch->board->port);
+	outb_p(0, (int)ch->board->port + 1);
+}
+
+/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
+
+static inline void pcxi_memwinon(struct board_info *b, unsigned int win)
+{
+               outb_p(inb((int)b->port) | FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_memwinoff(struct board_info *b, unsigned int win)
+{
+	outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port);
+}
+
+static inline void pcxi_globalwinon(struct channel *ch)
+{
+	outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_rxwinon(struct channel *ch)
+{
+		outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_txwinon(struct channel *ch)
+{
+		outb_p(FEPMEM, (int)ch->board->port);
+}
+
+static inline void pcxi_memoff(struct channel *ch)
+{
+	outb_p(0, (int)ch->board->port);
+}
+
+static inline void pcxi_assertgwinon(struct channel *ch)
+{
+	epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off");
+}
+
+static inline void pcxi_assertmemoff(struct channel *ch)
+{
+	epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on");
+}
+
+
+/* ----------------------------------------------------------------------
+	Not all of the cards need specific memory windowing routines.  Some
+	cards (Such as PCI) needs no windowing routines at all.  We provide
+	these do nothing routines so that the same code base can be used.
+	The driver will ALWAYS call a windowing routine if it thinks it needs
+	to; regardless of the card.  However, dependant on the card the routine
+	may or may not do anything.
+---------------------------------------------------------------------------*/
+
+static inline void dummy_memwinon(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_memwinoff(struct board_info *b, unsigned int win)
+{
+}
+
+static inline void dummy_globalwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_rxwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_txwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_memoff(struct channel *ch)
+{
+}
+
+static inline void dummy_assertgwinon(struct channel *ch)
+{
+}
+
+static inline void dummy_assertmemoff(struct channel *ch)
+{
+}
+
+/* ----------------- Begin verifyChannel function ----------------------- */
+static inline struct channel *verifyChannel(register struct tty_struct *tty)
+{ /* Begin verifyChannel */
+
+	/* --------------------------------------------------------------------
+		This routine basically provides a sanity check.  It insures that
+		the channel returned is within the proper range of addresses as
+		well as properly initialized.  If some bogus info gets passed in
+		through tty->driver_data this should catch it.
+	--------------------------------------------------------------------- */
+
+	if (tty) 
+	{ /* Begin if tty */
+
+		register struct channel *ch = (struct channel *)tty->driver_data;
+
+		if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) 
+		{
+			if (ch->magic == EPCA_MAGIC)
+				return ch;
+		}
+
+	} /* End if tty */
+
+	/* Else return a NULL for invalid */
+	return NULL;
+
+} /* End verifyChannel */
+
+/* ------------------ Begin pc_sched_event ------------------------- */
+
+static inline void pc_sched_event(struct channel *ch, int event)
+{ /* Begin pc_sched_event */
+
+
+	/* ----------------------------------------------------------------------
+		We call this to schedule interrupt processing on some event.  The 
+		kernel sees our request and calls the related routine in OUR driver.
+	-------------------------------------------------------------------------*/
+
+	ch->event |= 1 << event;
+	queue_task(&ch->tqueue, &tq_scheduler);
+
+
+} /* End pc_sched_event */
+
+/* ------------------ Begin epca_error ------------------------- */
+
+static void epca_error(int line, char *msg)
+{ /* Begin epca_error */
+
+	printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+	return;
+
+} /* End epca_error */
+
+/* ------------------ Begin pc_close ------------------------- */
+static void pc_close(struct tty_struct * tty, struct file * filp)
+{ /* Begin pc_close */
+
+	struct channel *ch;
+	unsigned long flags;
+
+	if (tty->driver.subtype == SERIAL_TYPE_INFO) 
+	{
+		return;
+	}
+
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if ch != NULL */
+
+		save_flags(flags);
+		cli();
+
+		if (tty_hung_up_p(filp)) 
+		{
+			restore_flags(flags);
+			return;
+		}
+
+		/* Check to see if the channel is open more than once */
+		if (ch->count-- > 1) 
+		{ /* Begin channel is open more than once */
+
+			/* -------------------------------------------------------------
+				Return without doing anything.  Someone might still be using
+				the channel.
+			---------------------------------------------------------------- */
+
+			restore_flags(flags);
+			return;
+		} /* End channel is open more than once */
+
+		/* Port open only once go ahead with shutdown & reset */
+
+		if (ch->count < 0) 
+		{
+			ch->count = 0;
+		}
+
+		/* ---------------------------------------------------------------
+			Let the rest of the driver know the channel is being closed.
+			This becomes important if an open is attempted before close 
+			is finished.
+		------------------------------------------------------------------ */
+
+		ch->asyncflags |= ASYNC_CLOSING;
+	
+		/* -------------------------------------------------------------
+			Save the termios structure, since this port may have
+			separate termios for callout and dialin.
+		--------------------------------------------------------------- */
+
+		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+			ch->normal_termios = *tty->termios;
+
+		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+			ch->callout_termios = *tty->termios;
+
+		tty->closing = 1;
+
+		if (ch->asyncflags & ASYNC_INITIALIZED) 
+		{
+			/* Setup an event to indicate when the transmit buffer empties */
+			setup_empty_event(tty, ch);		
+			tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+		}
+	
+		if (tty->driver.flush_buffer)
+			tty->driver.flush_buffer(tty);
+
+		if (tty->ldisc.flush_buffer)
+			tty->ldisc.flush_buffer(tty);
+
+		shutdown(ch);
+		tty->closing = 0;
+		ch->event = 0;
+		ch->tty = NULL;
+
+		if (ch->blocked_open) 
+		{ /* Begin if blocked_open */
+
+			if (ch->close_delay) 
+			{
+				current->state = TASK_INTERRUPTIBLE;
+				current->timeout = jiffies + ch->close_delay;
+				schedule();
+			}
+
+			wake_up_interruptible(&ch->open_wait);
+
+		} /* End if blocked_open */
+
+		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | 
+		                      ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
+		wake_up_interruptible(&ch->close_wait);
+
+#ifdef MODULE
+		MOD_DEC_USE_COUNT;
+#endif
+
+		restore_flags(flags);
+
+	} /* End if ch != NULL */
+
+} /* End pc_close */ 
+
+/* ------------------ Begin shutdown  ------------------------- */
+
+static void shutdown(struct channel *ch)
+{ /* Begin shutdown */
+
+	unsigned long flags;
+	struct tty_struct *tty;
+	volatile struct board_chan *bc;
+
+	if (!(ch->asyncflags & ASYNC_INITIALIZED)) 
+		return;
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+
+	bc = ch->brdchan;
+
+	/* ------------------------------------------------------------------
+		In order for an event to be generated on the receipt of data the
+		idata flag must be set. Since we are shutting down, this is not 
+		necessary clear this flag.
+	--------------------------------------------------------------------- */ 
+
+	if (bc)
+		bc->idata = 0;
+
+	tty = ch->tty;
+
+	/* ----------------------------------------------------------------
+	   If we're a modem control device and HUPCL is on, drop RTS & DTR.
+ 	------------------------------------------------------------------ */
+
+	if (tty->termios->c_cflag & HUPCL) 
+	{
+		ch->omodem &= ~(ch->m_rts | ch->m_dtr);
+		fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
+	}
+
+	memoff(ch);
+
+	/* ------------------------------------------------------------------
+		The channel has officialy been closed.  The next time it is opened
+		it will have to reinitialized.  Set a flag to indicate this.
+	---------------------------------------------------------------------- */
+
+	/* Prevent future Digi programmed interrupts from coming active */
+
+	ch->asyncflags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+
+} /* End shutdown */
+
+/* ------------------ Begin pc_hangup  ------------------------- */
+
+static void pc_hangup(struct tty_struct *tty)
+{ /* Begin pc_hangup */
+
+	struct channel *ch;
+	
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if ch != NULL */
+
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		if (tty->driver.flush_buffer)
+			tty->driver.flush_buffer(tty);
+
+		if (tty->ldisc.flush_buffer)
+			tty->ldisc.flush_buffer(tty);
+
+		shutdown(ch);
+
+#ifdef MODULE
+		if (ch->count)
+			MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+		
+
+		ch->tty   = NULL;
+		ch->event = 0;
+		ch->count = 0;
+		restore_flags(flags);
+		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE);
+		wake_up_interruptible(&ch->open_wait);
+
+	} /* End if ch != NULL */
+
+} /* End pc_hangup */
+
+/* ------------------ Begin pc_write  ------------------------- */
+
+static int pc_write(struct tty_struct * tty, int from_user,
+                    const unsigned char *buf, int bytesAvailable)
+{ /* Begin pc_write */
+
+	register unsigned int head, tail;
+	register int dataLen;
+	register int size;
+	register int amountCopied;
+
+
+	struct channel *ch;
+	unsigned long flags;
+	int remain;
+	volatile struct board_chan *bc;
+
+
+	/* ----------------------------------------------------------------
+		pc_write is primarily called directly by the kernel routine
+		tty_write (Though it can also be called by put_char) found in
+		tty_io.c.  pc_write is passed a line discipline buffer where 
+		the data to be written out is stored.  The line discipline 
+		implementation itself is done at the kernel level and is not 
+		brought into the driver.  
+	------------------------------------------------------------------- */
+
+	/* Stop users from hurting themselves on control minor */
+
+	if (tty->driver.subtype == SERIAL_TYPE_INFO) 
+	{
+		return (0) ;
+	}
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) == NULL)
+		return 0;
+
+	/* Make a pointer to the channel data structure found on the board. */
+
+	bc   = ch->brdchan;
+	size = ch->txbufsize;
+
+	if (from_user) 
+	{ /* Begin from_user */
+
+		save_flags(flags);
+		cli();
+
+		globalwinon(ch);
+
+		/* -----------------------------------------------------------------	
+			Anding against size will wrap the pointer back to its begining 
+			position if it is necessary.  This will only work if size is
+			a power of 2 which should always be the case.  Size is determined 
+			by the cards on board FEP/OS.
+		-------------------------------------------------------------------- */	
+
+		/* head refers to the next empty location in which data may be stored */ 
+
+		head = bc->tin & (size - 1);
+
+		/* tail refers to the next data byte to be transmitted */ 
+
+		tail = bc->tout;
+
+		/* Consider changing this to a do statement to make sure */
+
+		if (tail != bc->tout)
+			tail = bc->tout;
+
+		/* ------------------------------------------------------------------	
+			Anding against size will wrap the pointer back to its begining 
+			position if it is necessary.  This will only work if size is
+			a power of 2 which should always be the case.  Size is determined 
+			by the cards on board FEP/OS.
+		--------------------------------------------------------------------- */	
+
+		tail &= (size - 1);
+
+		/* -----------------------------------------------------------------
+			Two situations can affect how space in the transmit buffer
+			is calculated.  You can have a situation where the transmit
+			in pointer (tin) head has wrapped around and actually has a 
+			lower address than the transmit out pointer (tout) tail; or
+			the transmit in pointer (tin) head will not be wrapped around
+			yet, and have a higher address than the transmit out pointer
+			(tout) tail.  Obviously space available in the transmit buffer
+			is calculated differently for each case.
+
+			Example 1:
+			
+			Consider a 10 byte buffer where head is a pointer to the next
+			empty location in the buffer and tail is a pointer to the next 
+			byte to transmit.  In this example head will not have wrapped 
+			around and therefore head > tail.  
+
+			0      1      2      3      4      5      6      7      8      9   
+		                tail                               head
+
+			The above diagram shows that buffer locations 2,3,4,5 and 6 have
+			data to be transmited, while head points at the next empty
+			location.  To calculate how much space is available first we have
+			to determine if the head pointer (tin) has wrapped.  To do this
+			compare the head pointer to the tail pointer,  If head is equal
+			or greater than tail; then it has not wrapped; and the space may
+			be calculated by subtracting tail from head and then subtracting
+			that value from the buffers size.  A one is subtracted from the
+			new value to indicate how much space is available between the 
+			head pointer and end of buffer; as well as the space between the
+			begining of the buffer and the tail.  If the head is not greater
+			or equal to the tail this indicates that the head has wrapped
+			around to the begining of the buffer.  To calculate the space 
+			available in this case simply subtract head from tail.  This new 
+			value minus one represents the space available betwwen the head 
+			and tail pointers.  In this example head (7) is greater than tail (2)
+			and therefore has not wrapped around.  We find the space by first
+			subtracting tail from head (7-2=5).  We then subtract this value
+			from the buffer size of ten and subtract one (10-5-1=4).  The space
+			remaining is 4 bytes. 
+
+			Example 2:
+			
+			Consider a 10 byte buffer where head is a pointer to the next
+			empty location in the buffer and tail is a pointer to the next 
+			byte to transmit.  In this example head will wrapped around and 
+			therefore head < tail.  
+
+			0      1      2      3      4      5      6      7      8      9   
+		                head                               tail
+
+			The above diagram shows that buffer locations 7,8,9,0 and 1 have
+			data to be transmited, while head points at the next empty
+			location.  To find the space available we compare head to tail.  If
+			head is not equal to, or greater than tail this indicates that head
+			has wrapped around. In this case head (2) is not equal to, or
+			greater than tail (7) and therefore has already wrapped around.  To
+			calculate the available space between the two pointers we subtract
+			head from tail (7-2=5).  We then subtract one from this new value
+			(5-1=4).  We have 5 bytes empty remaining in the buffer.  Unlike the
+			previous example these five bytes are located between the head and
+			tail pointers. 
+
+		----------------------------------------------------------------------- */
+
+		dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
+
+		/* ----------------------------------------------------------------------
+			In this case bytesAvailable has been passed into pc_write and
+			represents the amount of data that needs to be written.  dataLen
+			represents the amount of space available on the card.  Whichever
+			value is smaller will be the amount actually written. 
+			bytesAvailable will then take on this newly calculated value.
+		---------------------------------------------------------------------- */
+
+		bytesAvailable = MIN(dataLen, bytesAvailable);
+
+		/* First we read the data in from the file system into a temp buffer */
+
+		if (bytesAvailable) 
+		{ /* Begin bytesAvailable */
+
+			/* Can the user buffer be accessed at the moment ? */
+			if (verify_area(VERIFY_READ, (char*)buf, bytesAvailable))
+				bytesAvailable = 0; /* Can't do; try again later */
+			else  /* Evidently it can, began transmission */
+			{ /* Begin if area verified */
+				/* ---------------------------------------------------------------
+					The below function reads data from user memory.  This routine
+					can not be used in an interrupt routine. (Because it may 
+					generate a page fault)  It can only be called while we can the
+					user context is accessible. 
+
+					The prototype is :
+					inline void copy_from_user(void * to, const void * from,
+					                          unsigned long count);
+
+					You must include <asm/segment.h>
+					I also think (Check hackers guide) that optimization must
+					be turned ON.  (Which sounds strange to me...)
+	
+					Remember copy_from_user WILL generate a page fault if the
+					user memory being accessed has been swapped out.  This can
+					cause this routine to temporarily sleep while this page
+					fault is occuring.
+				
+				----------------------------------------------------------------- */
+
+				copy_from_user(ch->tmp_buf, buf, bytesAvailable);
+
+			} /* End if area verified */
+
+		} /* End bytesAvailable */
+
+		/* ------------------------------------------------------------------ 
+			Set buf to this address for the moment.  tmp_buf was allocated in
+			post_fep_init.
+		--------------------------------------------------------------------- */
+		buf = ch->tmp_buf;
+		memoff(ch);
+		restore_flags(flags);
+
+	} /* End from_user */
+
+	/* All data is now local */
+
+	amountCopied = 0;
+	save_flags(flags);
+	cli();
+
+	globalwinon(ch);
+
+	head = bc->tin & (size - 1);
+	tail = bc->tout;
+
+	if (tail != bc->tout)
+		tail = bc->tout;
+	tail &= (size - 1);
+
+	/*	If head >= tail, head has not wrapped around. */ 
+	if (head >= tail) 
+	{ /* Begin head has not wrapped */
+
+		/* ---------------------------------------------------------------
+			remain (much like dataLen above) represents the total amount of
+			space available on the card for data.  Here dataLen represents
+			the space existing between the head pointer and the end of 
+			buffer.  This is important because a memcpy cannot be told to
+			automatically wrap around when it hits the buffer end.
+		------------------------------------------------------------------ */ 
+
+		dataLen = size - head;
+		remain = size - (head - tail) - 1;
+
+	} /* End head has not wrapped */
+	else 
+	{ /* Begin head has wrapped around */
+
+		remain = tail - head - 1;
+		dataLen = remain;
+
+	} /* End head has wrapped around */
+
+	/* -------------------------------------------------------------------
+			Check the space on the card.  If we have more data than 
+			space; reduce the amount of data to fit the space.
+	---------------------------------------------------------------------- */
+
+	bytesAvailable = MIN(remain, bytesAvailable);
+
+	txwinon(ch);
+	while (bytesAvailable > 0) 
+	{ /* Begin while there is data to copy onto card */
+
+		/* -----------------------------------------------------------------
+			If head is not wrapped, the below will make sure the first 
+			data copy fills to the end of card buffer.
+		------------------------------------------------------------------- */
+
+		dataLen = MIN(bytesAvailable, dataLen);
+		memcpy(ch->txptr + head, buf, dataLen);
+		buf += dataLen;
+		head += dataLen;
+		amountCopied += dataLen;
+		bytesAvailable -= dataLen;
+
+		if (head >= size) 
+		{
+			head = 0;
+			dataLen = tail;
+		}
+
+	} /* End while there is data to copy onto card */
+
+	ch->statusflags |= TXBUSY;
+	globalwinon(ch);
+	bc->tin = head;
+
+	if ((ch->statusflags & LOWWAIT) == 0) 
+	{
+		ch->statusflags |= LOWWAIT;
+		bc->ilow = 1;
+	}
+	memoff(ch);
+	restore_flags(flags);
+
+	return(amountCopied);
+
+} /* End pc_write */
+
+/* ------------------ Begin pc_put_char  ------------------------- */
+
+static void pc_put_char(struct tty_struct *tty, unsigned char c)
+{ /* Begin pc_put_char */
+
+   
+	pc_write(tty, 0, &c, 1);
+	return;
+
+} /* End pc_put_char */
+
+/* ------------------ Begin pc_write_room  ------------------------- */
+
+static int pc_write_room(struct tty_struct *tty)
+{ /* Begin pc_write_room */
+
+	int remain;
+	struct channel *ch;
+	unsigned long flags;
+	unsigned int head, tail;
+	volatile struct board_chan *bc;
+
+	remain = 0;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{
+		save_flags(flags);
+		cli();
+		globalwinon(ch);
+
+		bc   = ch->brdchan;
+		head = bc->tin & (ch->txbufsize - 1);
+		tail = bc->tout;
+
+		if (tail != bc->tout)
+			tail = bc->tout;
+		/* Wrap tail if necessary */
+		tail &= (ch->txbufsize - 1);
+
+		if ((remain = tail - head - 1) < 0 )
+			remain += ch->txbufsize;
+
+		if (remain && (ch->statusflags & LOWWAIT) == 0) 
+		{
+			ch->statusflags |= LOWWAIT;
+			bc->ilow = 1;
+		}
+		memoff(ch);
+		restore_flags(flags);
+	}
+
+	/* Return how much room is left on card */
+	return remain;
+
+} /* End pc_write_room */
+
+/* ------------------ Begin pc_chars_in_buffer  ---------------------- */
+
+static int pc_chars_in_buffer(struct tty_struct *tty)
+{ /* Begin pc_chars_in_buffer */
+
+	int chars;
+	unsigned int ctail, head, tail;
+	int remain;
+	unsigned long flags;
+	struct channel *ch;
+	volatile struct board_chan *bc;
+
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) == NULL)
+		return(0);
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+
+	bc = ch->brdchan;
+	tail = bc->tout;
+	head = bc->tin;
+	ctail = ch->mailbox->cout;
+
+	if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)
+		chars = 0;
+	else 
+	{ /* Begin if some space on the card has been used */
+
+		head = bc->tin & (ch->txbufsize - 1);
+		tail &= (ch->txbufsize - 1);
+
+		/*  --------------------------------------------------------------
+			The logic here is basically opposite of the above pc_write_room
+			here we are finding the amount of bytes in the buffer filled.
+			Not the amount of bytes empty.
+		------------------------------------------------------------------- */
+
+		if ((remain = tail - head - 1) < 0 )
+			remain += ch->txbufsize;
+
+		chars = (int)(ch->txbufsize - remain);
+
+		/* -------------------------------------------------------------  
+			Make it possible to wakeup anything waiting for output
+			in tty_ioctl.c, etc.
+
+			If not already set.  Setup an event to indicate when the
+			transmit buffer empties 
+		----------------------------------------------------------------- */
+
+		if (!(ch->statusflags & EMPTYWAIT))
+			setup_empty_event(tty,ch);
+
+	} /* End if some space on the card has been used */
+
+	memoff(ch);
+	restore_flags(flags);
+
+	/* Return number of characters residing on card. */
+	return(chars);
+
+} /* End pc_chars_in_buffer */
+
+/* ------------------ Begin pc_flush_buffer  ---------------------- */
+
+static void pc_flush_buffer(struct tty_struct *tty)
+{ /* Begin pc_flush_buffer */
+
+	unsigned int tail;
+	unsigned long flags;
+	struct channel *ch;
+	volatile struct board_chan *bc;
+
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) == NULL)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	globalwinon(ch);
+
+	bc   = ch->brdchan;
+	tail = bc->tout;
+
+	/* Have FEP move tout pointer; effectively flushing transmit buffer */
+
+	fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
+
+	memoff(ch);
+	restore_flags(flags);
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+} /* End pc_flush_buffer */
+
+/* ------------------ Begin pc_flush_chars  ---------------------- */
+
+static void pc_flush_chars(struct tty_struct *tty)
+{ /* Begin pc_flush_chars */
+
+	struct channel * ch;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		/* ----------------------------------------------------------------
+			If not already set and the transmitter is busy setup an event
+			to indicate when the transmit empties.
+		------------------------------------------------------------------- */
+
+		if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
+			setup_empty_event(tty,ch);
+
+		restore_flags(flags);
+	}
+
+} /* End pc_flush_chars */
+
+/* ------------------ Begin block_til_ready  ---------------------- */
+
+static int block_til_ready(struct tty_struct *tty, 
+                           struct file *filp, struct channel *ch)
+{ /* Begin block_til_ready */
+
+	struct wait_queue wait = {current, NULL};
+	int	retval, do_clocal = 0;
+	unsigned long flags;
+
+
+	if (tty_hung_up_p(filp))
+	{
+		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+			retval = -EAGAIN;
+		else
+			retval = -ERESTARTSYS;	
+		return(retval);
+	}
+
+	/* ----------------------------------------------------------------- 
+		If the device is in the middle of being closed, then block
+		until it's done, and then try again.
+	-------------------------------------------------------------------- */
+	if (ch->asyncflags & ASYNC_CLOSING) 
+	{
+		interruptible_sleep_on(&ch->close_wait);
+
+		if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+	}
+
+	/* ----------------------------------------------------------------- 
+	   If this is a callout device, then just make sure the normal
+	   device isn't being used.
+	-------------------------------------------------------------------- */
+
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) 
+	{ /* A cud device has been opened */
+		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+
+		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+		    (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
+		    (ch->session != current->session))
+		    return -EBUSY;
+
+		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+		    (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
+		    (ch->pgrp != current->pgrp))
+		    return -EBUSY;
+ 
+		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
+
+		return 0;
+	} /* End a cud device has been opened */
+
+	if (filp->f_flags & O_NONBLOCK) 
+	{
+		/* ----------------------------------------------------------------- 
+	  	 If non-blocking mode is set, then make the check up front
+	  	 and then exit.
+		-------------------------------------------------------------------- */
+
+		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+
+		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+		return 0;
+	}
+
+
+	if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) 
+	{
+		if (ch->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	else 
+	{
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+   /* Block waiting for the carrier detect and the line to become free */
+	
+	retval = 0;
+	add_wait_queue(&ch->open_wait, &wait);
+	save_flags(flags);
+	cli();
+
+
+	/* We dec count so that pc_close will know when to free things */
+	if (!tty_hung_up_p(filp))
+		ch->count--;
+
+	restore_flags(flags);
+
+	ch->blocked_open++;
+
+	while(1) 
+	{ /* Begin forever while  */
+
+		current->state = TASK_INTERRUPTIBLE;
+
+		if (tty_hung_up_p(filp) ||
+		    !(ch->asyncflags & ASYNC_INITIALIZED)) 
+		{
+			if (ch->asyncflags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+			break;
+		}
+
+		if (!(ch->asyncflags & ASYNC_CLOSING) && 
+		    !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
+			  (do_clocal || (ch->imodem & ch->dcd)))
+			break;
+
+		if (current->signal & ~current->blocked) 
+		{
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		/* ---------------------------------------------------------------
+			Allow someone else to be scheduled.  We will occasionaly go
+			through this loop until one of the above conditions change.
+			The below schedule call will allow other processes to enter and
+			prevent this loop from hogging the cpu.
+		------------------------------------------------------------------ */
+		schedule();
+
+	} /* End forever while  */
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&ch->open_wait, &wait);
+	cli();
+	if (!tty_hung_up_p(filp))
+		ch->count++;
+	restore_flags(flags);
+
+	ch->blocked_open--;
+
+	if (retval)
+		return retval;
+
+	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+
+	return 0;
+
+} /* End block_til_ready */	
+
+/* ------------------ Begin pc_open  ---------------------- */
+
+static int pc_open(struct tty_struct *tty, struct file * filp)
+{ /* Begin pc_open */
+
+	struct channel *ch;
+	unsigned long flags;
+	int line, retval, boardnum;
+	volatile struct board_chan *bc;
+	volatile unsigned int head;
+
+	/* Nothing "real" happens in open of control device */
+
+	if (tty->driver.subtype == SERIAL_TYPE_INFO) 
+	{
+		return (0) ;
+	}
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if (line < 0 || line >= nbdevs) 
+	{
+		printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");
+		tty->driver_data = NULL;
+		return(-ENODEV);
+	}
+
+#ifdef MODULE
+
+	MOD_INC_USE_COUNT;
+
+#endif
+
+	ch = &digi_channels[line];
+	boardnum = ch->boardnum;
+
+	/* Check status of board configured in system.  */
+
+	/* -----------------------------------------------------------------
+		I check to see if the epca_setup routine detected an user error.  
+		It might be better to put this in pc_init, but for the moment it
+		goes here.
+	---------------------------------------------------------------------- */
+
+	if (invalid_lilo_config)
+	{
+		if (setup_error_code & INVALID_BOARD_TYPE)
+			printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");
+
+		if (setup_error_code & INVALID_NUM_PORTS)
+			printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");
+
+		if (setup_error_code & INVALID_MEM_BASE)
+			printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");
+
+		if (setup_error_code & INVALID_PORT_BASE)
+			printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");
+
+		if (setup_error_code & INVALID_BOARD_STATUS)
+			printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");
+
+		if (setup_error_code & INVALID_ALTPIN)
+			printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");
+
+		tty->driver_data = NULL;   /* Mark this device as 'down' */
+		return(-ENODEV);
+	}
+
+	if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) 
+	{
+		tty->driver_data = NULL;   /* Mark this device as 'down' */
+		return(-ENODEV);
+	}
+	
+	if (( bc = ch->brdchan) == 0) 
+	{
+		tty->driver_data = NULL;
+		return(-ENODEV);
+	}
+
+	/* ------------------------------------------------------------------
+		Every time a channel is opened, increment a counter.  This is 
+		necessary because we do not wish to flush and shutdown the channel
+		until the last app holding the channel open, closes it.	 	
+	--------------------------------------------------------------------- */
+
+	ch->count++;
+
+	/* ----------------------------------------------------------------
+		Set a kernel structures pointer to our local channel 
+		structure.  This way we can get to it when passed only
+		a tty struct.
+	------------------------------------------------------------------ */
+
+	tty->driver_data = ch;
+	
+	/* ----------------------------------------------------------------
+		If this is the first time the channel has been opened, initialize
+		the tty->termios struct otherwise let pc_close handle it.
+	-------------------------------------------------------------------- */
+
+	/* Should this be here except for SPLIT termios ? */
+	if (ch->count == 1) 
+	{
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = ch->normal_termios;
+		else 
+			*tty->termios = ch->callout_termios;
+	}
+
+	ch->session = current->session;
+	ch->pgrp = current->pgrp;
+
+	save_flags(flags);
+	cli();
+
+	globalwinon(ch);
+	ch->statusflags = 0;
+
+	/* Save boards current modem status */
+	ch->imodem = bc->mstat;
+
+	/* ----------------------------------------------------------------
+	   Set receive head and tail ptrs to each other.  This indicates
+	   no data available to read.
+	----------------------------------------------------------------- */
+	head = bc->rin;
+	bc->rout = head;
+
+	/* Set the channels associated tty structure */
+	ch->tty = tty;
+
+	/* -----------------------------------------------------------------
+		The below routine generally sets up parity, baud, flow control 
+		issues, etc.... It effect both control flags and input flags.
+	-------------------------------------------------------------------- */
+	epcaparam(tty,ch);
+
+	ch->asyncflags |= ASYNC_INITIALIZED;
+	memoff(ch);
+
+	restore_flags(flags);
+
+	retval = block_til_ready(tty, filp, ch);
+	if (retval)
+	{
+		return retval;
+	}
+
+	/* -------------------------------------------------------------
+		Set this again in case a hangup set it to zero while this 
+		open() was waiting for the line...
+	--------------------------------------------------------------- */
+	ch->tty = tty;
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+
+	/* Enable Digi Data events */
+	bc->idata = 1;
+
+	memoff(ch);
+	restore_flags(flags);
+
+	return 0;
+
+} /* End pc_open */
+
+#ifdef MODULE
+/* -------------------- Begin init_module ---------------------- */
+int init_module()
+{ /* Begin init_module */
+
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	pc_init();
+
+	restore_flags(flags);
+
+	return(0);
+} /* End init_module */
+
+#endif
+#ifdef MODULE
+/* -------------------- Begin cleanup_module  ---------------------- */
+void cleanup_module()
+{ /* Begin cleanup_module */
+
+	int               count, crd;
+	struct board_info *bd;
+	struct channel    *ch;
+	unsigned long     flags;
+
+
+	save_flags(flags);
+	cli();
+
+	timer_table[DIGI_TIMER].fn = 0;
+
+	if ((tty_unregister_driver(&pc_driver)) ||  
+	    (tty_unregister_driver(&pc_callout)))
+	{
+		printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
+		restore_flags(flags);
+		return;
+	}
+
+	for (crd = 0; crd < num_cards; crd++) 
+	{ /* Begin for each card */
+
+		bd = &boards[crd];
+
+		if (!bd)
+		{ /* Begin sanity check */
+			printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
+			return;
+		} /* End sanity check */
+
+		ch = card_ptr[crd]; 
+
+		for (count = 0; count < bd->numports; count++, ch++) 
+		{ /* Begin for each port */
+
+			if (ch) 
+			{
+				if (ch->tty)
+					tty_hangup(ch->tty);
+				kfree_s(ch->tmp_buf, ch->txbufsize);
+			}
+
+		} /* End for each port */
+	} /* End for each card */
+
+
+	restore_flags(flags);
+
+} /* End cleanup_module */
+#endif /* MODULE */
+
+/* ------------------ Begin pc_init  ---------------------- */
+
+int pc_init(void)
+{ /* Begin pc_init */
+
+	/* ----------------------------------------------------------------
+		pc_init is called by the operating system during boot up prior to
+		any open calls being made.  In the older versions of Linux (Prior
+		to 2.0.0) an entry is made into tty_io.c.  A pointer to the last
+		memory location (from kernel space) used (kmem_start) is passed
+		to pc_init.  It is pc_inits responsibility to modify this value 
+		for any memory that the Digi driver might need and then return
+		this value to the operating system.  For example if the driver
+		wishes to allocate 1K of kernel memory, pc_init would return 
+		(kmem_start + 1024).  This memory (Between kmem_start and kmem_start
+		+ 1024) would then be available for use exclusively by the driver.  
+		In this case our driver does not allocate any of this kernel 
+		memory.
+	------------------------------------------------------------------*/
+
+	ulong flags, save_loops_per_sec; 
+	int crd;
+	struct board_info *bd;
+	unsigned char board_id = 0;
+	
+
+#ifdef ENABLE_PCI
+	int pci_boards_found, pci_count;
+
+	pci_count = 0;
+#endif /* ENABLE_PCI */
+
+	/* -----------------------------------------------------------------------
+		If epca_setup has not been ran by LILO set num_cards to defaults; copy
+		board structure defined by digiConfig into drivers board structure.
+		Note : If LILO has ran epca_setup then epca_setup will handle defining
+		num_cards as well as copying the data into the board structure.
+	-------------------------------------------------------------------------- */
+	if (!liloconfig)
+	{ /* Begin driver has been configured via. epcaconfig */
+
+		nbdevs = NBDEVS;
+		num_cards = NUMCARDS;
+		memcpy((void *)&boards, (void *)&static_boards,
+		       (sizeof(struct board_info) * NUMCARDS));
+	} /* End driver has been configured via. epcaconfig */
+
+	/* -----------------------------------------------------------------
+		Note : If lilo was used to configure the driver and the 
+		ignore epcaconfig option was choosen (digiepca=2) then 
+		nbdevs and num_cards will equal 0 at this point.  This is
+		okay; PCI cards will still be picked up if detected.
+	--------------------------------------------------------------------- */
+
+	/*  -----------------------------------------------------------
+		Set up interrupt, we will worry about memory allocation in
+		post_fep_init. 
+	--------------------------------------------------------------- */
+
+
+	printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+
+#ifdef ENABLE_PCI
+
+	/* ------------------------------------------------------------------
+		NOTE : This code assumes that the number of ports found in 
+		       the boards array is correct.  This could be wrong if
+		       the card in question is PCI (And therefore has no ports 
+		       entry in the boards structure.)  The rest of the 
+		       information will be valid for PCI because the begining
+		       of pc_init scans for PCI and determines i/o and base
+		       memory addresses.  I am not sure if it is possible to 
+		       read the number of ports supported by the card prior to
+		       it being booted (Since that is the state it is in when 
+		       pc_init is run).  Because it is not possible to query the
+		       number of supported ports until after the card has booted;
+		       we are required to calculate the card_ptrs as the card is	 
+		       is initialized (Inside post_fep_init).  The negative thing
+		       about this approach is that digiDload's call to GET_INFO
+		       will have a bad port value.  (Since this is called prior
+		       to post_fep_init.)
+
+	--------------------------------------------------------------------- */
+  
+	pci_boards_found = 0;
+	if (pcibios_present())
+	{
+		if(num_cards < MAXBOARDS)
+			pci_boards_found += init_PCI(num_cards);
+		num_cards += pci_boards_found;
+	}
+	else 
+	{
+		printk(KERN_ERR "<Error> - No PCI BIOS found\n");
+	}
+
+#endif /* ENABLE_PCI */
+
+	memset(&pc_driver, 0, sizeof(struct tty_driver));
+	memset(&pc_callout, 0, sizeof(struct tty_driver));
+	memset(&pc_info, 0, sizeof(struct tty_driver));
+
+	pc_driver.magic = TTY_DRIVER_MAGIC;
+	pc_driver.name = "ttyD"; 
+	pc_driver.major = DIGI_MAJOR; 
+	pc_driver.minor_start = 0;
+	pc_driver.num = MAX_ALLOC;
+	pc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	pc_driver.subtype = SERIAL_TYPE_NORMAL;
+	pc_driver.init_termios = tty_std_termios;
+	pc_driver.init_termios.c_iflag = 0;
+	pc_driver.init_termios.c_oflag = 0;
+
+	pc_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+	pc_driver.init_termios.c_lflag = 0;
+	pc_driver.flags = TTY_DRIVER_REAL_RAW;
+	pc_driver.refcount = &pc_refcount;
+	pc_driver.table = pc_table;
+	
+	/* pc_termios is an array of pointers pointing at termios structs */
+	/* The below should get the first pointer */
+	pc_driver.termios = pc_termios;
+	pc_driver.termios_locked = pc_termios_locked;
+
+	/* ------------------------------------------------------------------
+		Setup entry points for the driver.  These are primarily called by 
+		the kernel in tty_io.c and n_tty.c
+	--------------------------------------------------------------------- */
+
+	pc_driver.open = pc_open;
+	pc_driver.close = pc_close;
+	pc_driver.write = pc_write;
+	pc_driver.write_room = pc_write_room;
+	pc_driver.flush_buffer = pc_flush_buffer;
+	pc_driver.chars_in_buffer = pc_chars_in_buffer;
+	pc_driver.flush_chars = pc_flush_chars;
+	pc_driver.put_char = pc_put_char;
+	pc_driver.ioctl = pc_ioctl;
+	pc_driver.set_termios = pc_set_termios;
+	pc_driver.stop = pc_stop;
+	pc_driver.start = pc_start;
+	pc_driver.throttle = pc_throttle;
+	pc_driver.unthrottle = pc_unthrottle;
+	pc_driver.hangup = pc_hangup;
+	pc_callout = pc_driver;
+
+	pc_callout.name = "cud";
+	pc_callout.major = DIGICU_MAJOR;
+	pc_callout.minor_start = 0;
+	pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+	pc_callout.subtype = SERIAL_TYPE_CALLOUT;
+
+	pc_info = pc_driver;
+	pc_info.name = "digiCtl";
+	pc_info.major = DIGIINFOMAJOR;
+	pc_info.minor_start = 0;
+	pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+	pc_info.subtype = SERIAL_TYPE_INFO;
+
+
+	/* --------------------------------------------------------------------- 
+	   loops_per_sec hasn't been set at this point :-(, so fake it out... 
+	   I set it, so that I can use the __delay() function.
+	------------------------------------------------------------------------ */
+	save_loops_per_sec = loops_per_sec;
+	loops_per_sec = 13L * 500000L;
+
+	save_flags(flags);
+	cli();
+
+	for (crd = 0; crd < num_cards; crd++) 
+	{ /* Begin for each card */
+
+		/*  ------------------------------------------------------------------
+			This is where the appropriate memory handlers for the hardware is
+			set.  Everything at runtime blindly jumps through these vectors.
+		---------------------------------------------------------------------- */
+
+		/* defined in epcaconfig.h */
+		bd = &boards[crd];
+
+		switch (bd->type)
+		{ /* Begin switch on bd->type {board type} */
+			case PCXEM:
+			case EISAXEM:
+				bd->memwinon     = pcxem_memwinon ;
+				bd->memwinoff    = pcxem_memwinoff ;
+				bd->globalwinon  = pcxem_globalwinon ;
+				bd->txwinon      = pcxem_txwinon ;
+				bd->rxwinon      = pcxem_rxwinon ;
+				bd->memoff       = pcxem_memoff ;
+				bd->assertgwinon = dummy_assertgwinon;
+				bd->assertmemoff = dummy_assertmemoff;
+				break;
+
+			case PCIXEM:
+			case PCIXRJ:
+			case PCIXR:
+				bd->memwinon     = dummy_memwinon;
+				bd->memwinoff    = dummy_memwinoff;
+				bd->globalwinon  = dummy_globalwinon;
+				bd->txwinon      = dummy_txwinon;
+				bd->rxwinon      = dummy_rxwinon;
+				bd->memoff       = dummy_memoff;
+				bd->assertgwinon = dummy_assertgwinon;
+				bd->assertmemoff = dummy_assertmemoff;
+				break;
+
+			case PCXE:
+			case PCXEVE:
+
+				bd->memwinon     = pcxe_memwinon;
+				bd->memwinoff    = pcxe_memwinoff;
+				bd->globalwinon  = pcxe_globalwinon;
+				bd->txwinon      = pcxe_txwinon;
+				bd->rxwinon      = pcxe_rxwinon;
+				bd->memoff       = pcxe_memoff;
+				bd->assertgwinon = dummy_assertgwinon;
+				bd->assertmemoff = dummy_assertmemoff;
+				break;
+
+			case PCXI:
+			case PC64XE:
+
+				bd->memwinon     = pcxi_memwinon;
+				bd->memwinoff    = pcxi_memwinoff;
+				bd->globalwinon  = pcxi_globalwinon;
+				bd->txwinon      = pcxi_txwinon;
+				bd->rxwinon      = pcxi_rxwinon;
+				bd->memoff       = pcxi_memoff;
+				bd->assertgwinon = pcxi_assertgwinon;
+				bd->assertmemoff = pcxi_assertmemoff;
+				break;
+
+			default:
+				break;
+
+		} /* End switch on bd->type */
+
+		/* ---------------------------------------------------------------
+			Some cards need a memory segment to be defined for use in 
+			transmit and receive windowing operations.  These boards
+			are listed in the below switch.  In the case of the XI the
+			amount of memory on the board is variable so the memory_seg
+			is also variable.  This code determines what they segment 
+			should be.
+		----------------------------------------------------------------- */
+
+		switch (bd->type)
+		{ /* Begin switch on bd->type {board type} */
+
+			case PCXE:
+			case PCXEVE:
+			case PC64XE:
+				bd->memory_seg = 0xf000;
+			break;
+
+			case PCXI:
+				board_id = inb((int)bd->port);
+				if ((board_id & 0x1) == 0x1) 
+				{ /* Begin its an XI card */ 
+
+					/* Is it a 64K board */
+					if ((board_id & 0x30) == 0) 
+						bd->memory_seg = 0xf000;
+
+					/* Is it a 128K board */
+					if ((board_id & 0x30) == 0x10) 
+						bd->memory_seg = 0xe000;
+
+					/* Is is a 256K board */	
+					if ((board_id & 0x30) == 0x20) 
+						bd->memory_seg = 0xc000;
+
+					/* Is it a 512K board */
+					if ((board_id & 0x30) == 0x30) 
+						bd->memory_seg = 0x8000;
+
+				} /* End it is an XI card */
+				else
+				{
+					printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+				}
+			break;
+
+		} /* End switch on bd->type */
+
+	} /* End for each card */
+
+	if (tty_register_driver(&pc_driver))
+		panic("Couldn't register Digi PC/ driver");
+
+	if (tty_register_driver(&pc_callout))
+		panic("Couldn't register Digi PC/ callout");
+
+	if (tty_register_driver(&pc_info))
+		panic("Couldn't register Digi PC/ info ");
+
+	loops_per_sec = save_loops_per_sec;  /* reset it to what it should be */
+
+	/* -------------------------------------------------------------------
+	   Start up the poller to check for events on all enabled boards
+	---------------------------------------------------------------------- */
+
+	timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+	timer_table[DIGI_TIMER].expires = 0;
+
+	restore_flags(flags);
+
+	timer_active |= 1 << DIGI_TIMER;
+	return 0;
+
+} /* End pc_init */
+
+/* ------------------ Begin post_fep_init  ---------------------- */
+
+static void post_fep_init(unsigned int crd)
+{ /* Begin post_fep_init */
+
+	int i;
+	unchar *memaddr;
+	volatile struct global_data *gd;
+	struct board_info *bd;
+	volatile struct board_chan *bc;
+	struct channel *ch; 
+	int shrinkmem = 0, lowwater ; 
+ 
+	/*  -------------------------------------------------------------
+		This call is made by the user via. the ioctl call DIGI_INIT.
+		It is resposible for setting up all the card specific stuff.
+	---------------------------------------------------------------- */
+	bd = &boards[crd];
+
+	/* -----------------------------------------------------------------
+		If this is a PCI board, get the port info.  Remember PCI cards
+		do not have entries into the epcaconfig.h file, so we can't get 
+		the number of ports from it.  Unfortunetly, this means that anyone
+		doing a DIGI_GETINFO before the board has booted will get an invalid
+		number of ports returned (It should return 0).  Calls to DIGI_GETINFO
+		after DIGI_INIT has been called will return the proper values. 
+	------------------------------------------------------------------- */
+
+	if (bd->type >= PCIXEM) /* If the board in question is PCI */
+	{ /* Begin get PCI number of ports */
+
+		/* --------------------------------------------------------------------
+			Below we use XEMPORTS as a memory offset regardless of which PCI
+			card it is.  This is because all of the supported PCI cards have
+			the same memory offset for the channel data.  This will have to be
+			changed if we ever develop a PCI/XE card.  NOTE : The FEP manual
+			states that the port offset is 0xC22 as opposed to 0xC02.  This is
+			only true for PC/XE, and PC/XI cards; not for the XEM, or CX series.
+			On the PCI cards the number of ports is determined by reading a 
+			ID PROM located in the box attached to the card.  The card can then
+			determine the index the id to determine the number of ports available.
+			(FYI - The id should be located at 0x1ac (And may use up to 4 bytes
+			if the box in question is a XEM or CX)).  
+		------------------------------------------------------------------------ */ 
+
+		bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)
+                                                       (bd->re_map_membase + XEMPORTS));
+
+		
+		epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+		nbdevs += (bd->numports);
+
+	} /* End get PCI number of ports */
+
+	if (crd != 0)
+		card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
+	else
+		card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
+
+	ch = card_ptr[crd];
+
+
+	epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
+
+	if (bd->membase < (unsigned char *)0x100000)
+		memaddr = (unchar *) bd->membase;
+	else /* Else get special mapped memory above RAM */
+		memaddr = (unchar *)bd->re_map_membase;
+
+	/* 
+	   The below command is necessary because newer kernels (2.1.x and
+	   up) do not have a 1:1 virtual to physical mapping.  The below
+	   call adjust for that.
+	*/
+
+	memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+	/* -----------------------------------------------------------------
+		The below assignment will set bc to point at the BEGINING of
+		the cards channel structures.  For 1 card there will be between
+		8 and 64 of these structures.
+	-------------------------------------------------------------------- */
+
+	bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
+
+	/* -------------------------------------------------------------------
+		The below assignment will set gd to point at the BEGINING of
+		global memory address 0xc00.  The first data in that global
+		memory actually starts at address 0xc1a.  The command in 
+		pointer begins at 0xd10.
+	---------------------------------------------------------------------- */
+
+	gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
+
+	/* --------------------------------------------------------------------
+		XEPORTS (address 0xc22) points at the number of channels the
+		card supports. (For 64XE, XI, XEM, and XR use 0xc02)
+	----------------------------------------------------------------------- */
+
+	if (((bd->type == PCXEVE) | (bd->type == PCXE)) &&
+	    (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
+		shrinkmem = 1;
+	if (bd->type < PCIXEM)
+		request_region((int)bd->port, 4, board_desc[bd->type]);
+
+	memwinon(bd, 0);
+
+	/*  --------------------------------------------------------------------
+		Remember ch is the main drivers channels structure, while bc is 
+	   the cards channel structure.
+	------------------------------------------------------------------------ */
+
+	/* For every port on the card do ..... */
+
+	for (i = 0; i < bd->numports; i++, ch++, bc++) 
+	{ /* Begin for each port */
+
+		ch->brdchan        = bc;
+		ch->mailbox        = gd; 
+		ch->tqueue.routine = do_softint;
+		ch->tqueue.data    = ch;
+		ch->board          = &boards[crd];
+
+		switch (bd->type)
+		{ /* Begin switch bd->type */
+
+			/* ----------------------------------------------------------------
+				Since some of the boards use different bitmaps for their
+				control signals we cannot hard code these values and retain
+				portability.  We virtualize this data here.
+			------------------------------------------------------------------- */
+			case EISAXEM:
+			case PCXEM:
+			case PCIXEM:
+			case PCIXRJ:
+			case PCIXR:
+				ch->m_rts = 0x02 ;
+				ch->m_dcd = 0x80 ; 
+				ch->m_dsr = 0x20 ;
+				ch->m_cts = 0x10 ;
+				ch->m_ri  = 0x40 ;
+				ch->m_dtr = 0x01 ;
+				break;
+
+			case PCXE:
+			case PCXEVE:
+			case PCXI:
+			case PC64XE:
+				ch->m_rts = 0x02 ;
+				ch->m_dcd = 0x08 ; 
+				ch->m_dsr = 0x10 ;
+				ch->m_cts = 0x20 ;
+				ch->m_ri  = 0x40 ;
+				ch->m_dtr = 0x80 ;
+				break;
+	
+		} /* End switch bd->type */
+
+		if (boards[crd].altpin) 
+		{
+			ch->dsr = ch->m_dcd;
+			ch->dcd = ch->m_dsr;
+			ch->digiext.digi_flags |= DIGI_ALTPIN;
+		}
+		else 
+		{ 
+			ch->dcd = ch->m_dcd;
+			ch->dsr = ch->m_dsr;
+		}
+	
+		ch->boardnum   = crd;
+		ch->channelnum = i;
+		ch->magic      = EPCA_MAGIC;
+		ch->tty        = 0;
+
+		if (shrinkmem) 
+		{
+			fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
+			shrinkmem = 0;
+		}
+
+		switch (bd->type)
+		{ /* Begin switch bd->type */
+
+			case PCIXEM:
+			case PCIXRJ:
+			case PCIXR:
+				/* Cover all the 2MEG cards */
+				ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff);
+				ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff);
+				ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+				ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+				break;
+
+			case PCXEM:
+			case EISAXEM:
+				/* Cover all the 32K windowed cards */
+				/* Mask equal to window size - 1 */
+				ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff);
+				ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff);
+				ch->txwin = FEPWIN | ((bc->tseg) >> 11);
+				ch->rxwin = FEPWIN | ((bc->rseg) >> 11);
+				break;
+
+			case PCXEVE:
+			case PCXE:
+				ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff);
+				ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9);
+				ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff);
+				ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 );
+				break;
+
+			case PCXI:
+			case PC64XE:
+				ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4);
+				ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4);
+				ch->txwin = ch->rxwin = 0;
+				break;
+
+		} /* End switch bd->type */
+
+		ch->txbufhead = 0;
+		ch->txbufsize = bc->tmax + 1;
+	
+		ch->rxbufhead = 0;
+		ch->rxbufsize = bc->rmax + 1;
+	
+		lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
+
+		/* Set transmitter low water mark */
+		fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
+
+		/* Set receiver low water mark */
+
+		fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
+
+		/* Set receiver high water mark */
+
+		fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
+
+		bc->edelay = 100;
+		bc->idata = 1;
+	
+		ch->startc  = bc->startc;
+		ch->stopc   = bc->stopc;
+		ch->startca = bc->startca;
+		ch->stopca  = bc->stopca;
+	
+		ch->fepcflag = 0;
+		ch->fepiflag = 0;
+		ch->fepoflag = 0;
+		ch->fepstartc = 0;
+		ch->fepstopc = 0;
+		ch->fepstartca = 0;
+		ch->fepstopca = 0;
+	
+		ch->close_delay = 50;
+		ch->count = 0;
+		ch->blocked_open = 0;
+		ch->callout_termios = pc_callout.init_termios;
+		ch->normal_termios = pc_driver.init_termios;
+		ch->open_wait = 0;
+		ch->close_wait = 0;
+		ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
+		if (!(ch->tmp_buf))
+		{
+			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
+
+		}
+		memset((void *)ch->tmp_buf,0,ch->txbufsize);
+	} /* End for each port */
+
+	printk(KERN_INFO 
+	        "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 
+	        VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+	sprintf(mesg, 
+	        "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 
+	        VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+	console_print(mesg);
+
+	memwinoff(bd, 0);
+
+} /* End post_fep_init */
+
+/* --------------------- Begin epcapoll  ------------------------ */
+
+static void epcapoll(unsigned long ignored)
+{ /* Begin epcapoll */
+
+	unsigned long flags;
+	int crd;
+	volatile unsigned int head, tail;
+	struct channel *ch;
+	struct board_info *bd;
+
+	/* -------------------------------------------------------------------
+		This routine is called upon every timer interrupt.  Even though
+		the Digi series cards are capable of generating interupts this 
+		method of non-looping polling is more efficient.  This routine
+		checks for card generated events (Such as receive data, are transmit
+		buffer empty) and acts on those events.
+	----------------------------------------------------------------------- */
+	
+	save_flags(flags);
+	cli();
+
+	for (crd = 0; crd < num_cards; crd++) 
+	{ /* Begin for each card */
+
+		bd = &boards[crd];
+		ch = card_ptr[crd];
+
+		if ((bd->status == DISABLED) || digi_poller_inhibited)
+			continue; /* Begin loop next interation */
+
+		/* -----------------------------------------------------------
+			assertmemoff is not needed here; indeed it is an empty subroutine.
+			It is being kept because future boards may need this as well as
+			some legacy boards.
+		---------------------------------------------------------------- */
+
+		assertmemoff(ch);
+
+		globalwinon(ch);
+
+		/* ---------------------------------------------------------------
+			In this case head and tail actually refer to the event queue not
+			the transmit or receive queue.
+		------------------------------------------------------------------- */
+
+		head = ch->mailbox->ein;
+		tail = ch->mailbox->eout;
+		
+		/* If head isn't equal to tail we have an event */
+
+		if (head != tail)
+			doevent(crd);
+
+		memoff(ch);
+
+	} /* End for each card */
+
+	timer_table[DIGI_TIMER].fn = (void *)epcapoll;
+	timer_table[DIGI_TIMER].expires = jiffies + (HZ / 25);
+	timer_active |= 1 << DIGI_TIMER;
+
+	restore_flags(flags);
+
+} /* End epcapoll */
+
+/* --------------------- Begin doevent  ------------------------ */
+
+static void doevent(int crd)
+{ /* Begin doevent */
+
+	volatile unchar *eventbuf;
+	struct channel *ch, *chan0;
+	static struct tty_struct *tty;
+	volatile struct board_info *bd;
+	volatile struct board_chan *bc;
+	register volatile unsigned int tail, head;
+	register int event, channel;
+	register int mstat, lstat;
+
+	/* -------------------------------------------------------------------
+		This subroutine is called by epcapoll when an event is detected 
+		in the event queue.  This routine responds to those events.
+	--------------------------------------------------------------------- */
+
+	bd = &boards[crd];
+
+	chan0 = card_ptr[crd];
+	epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
+
+	assertgwinon(chan0);
+
+	while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) 
+	{ /* Begin while something in event queue */
+
+		assertgwinon(chan0);
+
+		if (bd->membase < (unsigned char *)0x100000)
+			eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->membase + tail + ISTART));
+		else
+		{
+			eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
+		}
+
+		/* Get the channel the event occured on */
+		channel = eventbuf[0];
+
+		/* Get the actual event code that occured */
+		event = eventbuf[1];
+
+		/*  ----------------------------------------------------------------
+			The two assignments below get the current modem status (mstat)
+			and the previous modem status (lstat).  These are useful becuase
+			an event could signal a change in modem signals itself.
+		------------------------------------------------------------------- */
+
+		mstat = eventbuf[2];
+		lstat = eventbuf[3];
+
+		ch = chan0 + channel;
+
+		if ((unsigned)channel >= bd->numports || !ch) 
+		{ 
+			if (channel >= bd->numports)
+				ch = chan0;
+			bc = ch->brdchan;
+			goto next;
+		}
+
+		if ((bc = ch->brdchan) == NULL)
+			goto next;
+
+		if (event & DATA_IND) 
+		{ /* Begin DATA_IND */
+
+			receive_data(ch);
+			assertgwinon(ch);
+
+		} /* End DATA_IND */
+		else
+		if (event & MODEMCHG_IND) 
+		{ /* Begin MODEMCHG_IND */
+
+			/* A modem signal change has been indicated */
+
+			ch->imodem = mstat;
+
+			if (ch->asyncflags & ASYNC_CHECK_CD) 
+			{
+				if (mstat & ch->dcd)  /* We are now receiving dcd */
+					wake_up_interruptible(&ch->open_wait);
+				else
+					pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+			}
+
+		} /* End MODEMCHG_IND */
+
+		tty = ch->tty;
+		if (tty) 
+		{ /* Begin if valid tty */
+
+			if (event & BREAK_IND) 
+			{ /* Begin if BREAK_IND */
+
+				/* A break has been indicated */
+
+				tty->flip.count++;
+				*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+
+				*tty->flip.char_buf_ptr++ = 0;
+
+				tty_schedule_flip(tty); 
+
+			} /* End if BREAK_IND */
+			else
+			if (event & LOWTX_IND) 
+			{ /* Begin LOWTX_IND */
+
+				if (ch->statusflags & LOWWAIT) 
+				{ /* Begin if LOWWAIT */
+
+					ch->statusflags &= ~LOWWAIT;
+					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+						  tty->ldisc.write_wakeup)
+						(tty->ldisc.write_wakeup)(tty);
+					wake_up_interruptible(&tty->write_wait);
+
+				} /* End if LOWWAIT */
+
+			} /* End LOWTX_IND */
+			else
+			if (event & EMPTYTX_IND) 
+			{ /* Begin EMPTYTX_IND */
+
+				/* This event is generated by setup_empty_event */
+
+				ch->statusflags &= ~TXBUSY;
+				if (ch->statusflags & EMPTYWAIT) 
+				{ /* Begin if EMPTYWAIT */
+
+					ch->statusflags &= ~EMPTYWAIT;
+					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+						  tty->ldisc.write_wakeup)
+						(tty->ldisc.write_wakeup)(tty);
+
+					wake_up_interruptible(&tty->write_wait);
+
+				} /* End if EMPTYWAIT */
+
+			} /* End EMPTYTX_IND */
+
+		} /* End if valid tty */
+
+
+	next:
+		globalwinon(ch);
+
+		if (!bc)
+			printk(KERN_ERR "<Error> - bc == NULL in doevent!\n");
+		else 
+			bc->idata = 1;
+
+		chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4);
+		globalwinon(chan0);
+
+	} /* End while something in event queue */
+
+} /* End doevent */
+
+/* --------------------- Begin fepcmd  ------------------------ */
+
+static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
+                   int byte2, int ncmds, int bytecmd)
+{ /* Begin fepcmd */
+
+	unchar *memaddr;
+	unsigned int head, cmdTail, cmdStart, cmdMax;
+	long count;
+	int n;
+
+	/* This is the routine in which commands may be passed to the card. */
+
+	if (ch->board->status == DISABLED)
+	{
+		return;
+	}
+
+	assertgwinon(ch);
+
+	/* Remember head (As well as max) is just an offset not a base addr */
+	head = ch->mailbox->cin;
+
+	/* cmdStart is a base address */
+	cmdStart = ch->mailbox->cstart;
+
+	/* ------------------------------------------------------------------
+		We do the addition below because we do not want a max pointer 
+		relative to cmdStart.  We want a max pointer that points at the 
+		physical end of the command queue.
+	-------------------------------------------------------------------- */
+
+	cmdMax = (cmdStart + 4 + (ch->mailbox->cmax));
+
+	if (ch->board->membase < (unsigned char *)0x100000)
+		memaddr = ch->board->membase;
+	else
+		memaddr = ch->board->re_map_membase;
+
+	/* 
+	   The below command is necessary because newer kernels (2.1.x and
+	   up) do not have a 1:1 virtual to physical mapping.  The below
+	   call adjust for that.
+	*/
+
+	memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);
+
+	if (head >= (cmdMax - cmdStart) || (head & 03)) 
+	{
+		printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, 
+              cmd, head);
+		printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, 
+              cmdMax, cmdStart);
+		return;
+	}
+
+	if (bytecmd) 
+	{
+		*(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+
+		*(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+		/* Below word_or_byte is bits to set */
+		*(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte;
+		/* Below byte2 is bits to reset */
+		*(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2;
+
+	} 
+	else 
+	{
+		*(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd;
+		*(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum;
+		*(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte;
+	}
+
+	head = (head + 4) & (cmdMax - cmdStart - 4);
+	ch->mailbox->cin = head;
+
+	count = FEPTIMEOUT;
+
+	for (;;) 
+	{ /* Begin forever loop */
+
+		count--;
+		if (count == 0) 
+		{
+			printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
+			return;
+		}
+
+		head = ch->mailbox->cin;
+		cmdTail = ch->mailbox->cout;
+
+		n = (head - cmdTail) & (cmdMax - cmdStart - 4);
+
+		/* ----------------------------------------------------------
+			Basically this will break when the FEP acknowledges the 
+			command by incrementing cmdTail (Making it equal to head).
+		------------------------------------------------------------- */
+
+		if (n <= ncmds * (sizeof(short) * 4))
+			break; /* Well nearly forever :-) */
+
+	} /* End forever loop */
+
+} /* End fepcmd */
+
+/* ---------------------------------------------------------------------
+	Digi products use fields in their channels structures that are very
+	similar to the c_cflag and c_iflag fields typically found in UNIX
+	termios structures.  The below three routines allow mappings 
+	between these hardware "flags" and their respective Linux flags.
+------------------------------------------------------------------------- */
+ 
+/* --------------------- Begin termios2digi_h -------------------- */
+
+static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_h */
+
+	unsigned res = 0;
+
+	if (cflag & CRTSCTS) 
+	{
+		ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
+		res |= ((ch->m_cts) | (ch->m_rts));
+	}
+
+	if (ch->digiext.digi_flags & RTSPACE)
+		res |= ch->m_rts;
+
+	if (ch->digiext.digi_flags & DTRPACE)
+		res |= ch->m_dtr;
+
+	if (ch->digiext.digi_flags & CTSPACE)
+		res |= ch->m_cts;
+
+	if (ch->digiext.digi_flags & DSRPACE)
+		res |= ch->dsr;
+
+	if (ch->digiext.digi_flags & DCDPACE)
+		res |= ch->dcd;
+
+	if (res & (ch->m_rts))
+		ch->digiext.digi_flags |= RTSPACE;
+
+	if (res & (ch->m_cts))
+		ch->digiext.digi_flags |= CTSPACE;
+
+	return res;
+
+} /* End termios2digi_h */
+
+/* --------------------- Begin termios2digi_i -------------------- */
+static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
+{ /* Begin termios2digi_i */
+
+	unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | 
+	                        INPCK | ISTRIP|IXON|IXANY|IXOFF);
+	
+	if (ch->digiext.digi_flags & DIGI_AIXON)
+		res |= IAIXON;
+	return res;
+
+} /* End termios2digi_i */
+
+/* --------------------- Begin termios2digi_c -------------------- */
+
+static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
+{ /* Begin termios2digi_c */
+
+	unsigned res = 0;
+
+#ifdef SPEED_HACK
+	/* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
+	if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
+	if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
+#endif /* SPEED_HACK */
+
+	if (cflag & CBAUDEX)
+	{ /* Begin detected CBAUDEX */
+
+		ch->digiext.digi_flags |= DIGI_FAST;
+
+		/* -------------------------------------------------------------
+		   HUPCL bit is used by FEP to indicate fast baud
+		   table is to be used.
+		----------------------------------------------------------------- */
+
+		res |= FEP_HUPCL;
+
+	} /* End detected CBAUDEX */
+	else ch->digiext.digi_flags &= ~DIGI_FAST; 
+
+	/* -------------------------------------------------------------------
+		CBAUD has bit position 0x1000 set these days to indicate Linux
+		baud rate remap.  Digi hardware can't handle the bit assignment.
+		(We use a different bit assignment for high speed.).  Clear this
+		bit out.
+	---------------------------------------------------------------------- */
+	res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
+
+	/* -------------------------------------------------------------
+		This gets a little confusing.  The Digi cards have their own
+		representation of c_cflags controling baud rate.  For the most
+		part this is identical to the Linux implementation.  However;
+		Digi supports one rate (76800) that Linux doesn't.  This means 
+		that the c_cflag entry that would normally mean 76800 for Digi
+		actually means 115200 under Linux.  Without the below mapping,
+		a stty 115200 would only drive the board at 76800.  Since 
+		the rate 230400 is also found after 76800, the same problem afflicts	
+		us when we choose a rate of 230400.  Without the below modificiation
+		stty 230400 would actually give us 115200.
+
+		There are two additional differences.  The Linux value for CLOCAL
+		(0x800; 0004000) has no meaning to the Digi hardware.  Also in 
+		later releases of Linux; the CBAUD define has CBAUDEX (0x1000;
+		0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX
+		should be checked for a screened out prior to termios2digi_c 
+		returning.  Since CLOCAL isn't used by the board this can be
+		ignored as long as the returned value is used only by Digi hardware. 
+	----------------------------------------------------------------- */
+
+	if (cflag & CBAUDEX)
+	{
+		/* -------------------------------------------------------------
+			The below code is trying to guarantee that only baud rates
+			115200 and 230400 are remapped.  We use exclusive or because
+			the various baud rates share common bit positions and therefore
+			can't be tested for easily.
+		----------------------------------------------------------------- */
+
+				
+		if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || 
+		    (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
+		{
+			res += 1;
+		}
+	}
+
+	return res;
+
+} /* End termios2digi_c */
+
+/* --------------------- Begin epcaparam  ----------------------- */
+
+static void epcaparam(struct tty_struct *tty, struct channel *ch)
+{ /* Begin epcaparam */
+
+	unsigned int cmdHead;
+	struct termios *ts;
+	volatile struct board_chan *bc;
+	unsigned mval, hflow, cflag, iflag;
+
+	bc = ch->brdchan;
+	epcaassert(bc !=0, "bc out of range");
+
+	assertgwinon(ch);
+
+	ts = tty->termios;
+
+	if ((ts->c_cflag & CBAUD) == 0) 
+	{ /* Begin CBAUD detected */
+
+		cmdHead = bc->rin;
+		bc->rout = cmdHead;
+		cmdHead = bc->tin;
+
+		/* Changing baud in mid-stream transmission can be wonderful */
+		/* ---------------------------------------------------------------
+			Flush current transmit buffer by setting cmdTail pointer (tout)
+			to cmdHead pointer (tin).  Hopefully the transmit buffer is empty.
+		----------------------------------------------------------------- */
+
+		fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
+		mval = 0;
+
+	} /* End CBAUD detected */
+	else 
+	{ /* Begin CBAUD not detected */
+
+		/* -------------------------------------------------------------------
+			c_cflags have changed but that change had nothing to do with BAUD.
+			Propagate the change to the card.
+		---------------------------------------------------------------------- */ 
+
+		cflag = termios2digi_c(ch, ts->c_cflag);
+
+		if (cflag != ch->fepcflag) 
+		{
+			ch->fepcflag = cflag;
+			/* Set baud rate, char size, stop bits, parity */
+			fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
+		}
+
+
+		/* ----------------------------------------------------------------
+			If the user has not forced CLOCAL and if the device is not a 
+			CALLOUT device (Which is always CLOCAL) we set flags such that
+			the driver will wait on carrier detect.
+		------------------------------------------------------------------- */
+
+		if ((ts->c_cflag & CLOCAL) || (tty->driver.subtype == SERIAL_TYPE_CALLOUT))
+		{ /* Begin it is a cud device or a ttyD device with CLOCAL on */
+			ch->asyncflags &= ~ASYNC_CHECK_CD;
+		} /* End it is a cud device or a ttyD device with CLOCAL on */
+		else
+		{ /* Begin it is a ttyD device */
+			ch->asyncflags |= ASYNC_CHECK_CD;
+		} /* End it is a ttyD device */
+
+		mval = ch->m_dtr | ch->m_rts;
+
+	} /* End CBAUD not detected */
+
+	iflag = termios2digi_i(ch, ts->c_iflag);
+
+	/* Check input mode flags */
+
+	if (iflag != ch->fepiflag) 
+	{
+		ch->fepiflag = iflag;
+
+		/* ---------------------------------------------------------------
+			Command sets channels iflag structure on the board. Such things 
+			as input soft flow control, handeling of parity errors, and
+			break handeling are all set here.
+		------------------------------------------------------------------- */
+
+		/* break handeling, parity handeling, input stripping, flow control chars */
+		fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
+	}
+
+	/* ---------------------------------------------------------------
+		Set the board mint value for this channel.  This will cause hardware
+		events to be generated each time the DCD signal (Described in mint) 
+		changes.	
+	------------------------------------------------------------------- */
+	bc->mint = ch->dcd;
+
+	if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
+		if (ch->digiext.digi_flags & DIGI_FORCEDCD)
+			bc->mint = 0;
+
+	ch->imodem = bc->mstat;
+
+	hflow = termios2digi_h(ch, ts->c_cflag);
+
+	if (hflow != ch->hflow) 
+	{
+		ch->hflow = hflow;
+
+		/* --------------------------------------------------------------
+			Hard flow control has been selected but the board is not
+			using it.  Activate hard flow control now.
+		----------------------------------------------------------------- */
+
+		fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
+	}
+	
+
+	mval ^= ch->modemfake & (mval ^ ch->modem);
+
+	if (ch->omodem ^ mval) 
+	{
+		ch->omodem = mval;
+
+		/* --------------------------------------------------------------
+			The below command sets the DTR and RTS mstat structure.  If
+			hard flow control is NOT active these changes will drive the
+			output of the actual DTR and RTS lines.  If hard flow control 
+			is active, the changes will be saved in the mstat structure and
+			only asserted when hard flow control is turned off. 
+		----------------------------------------------------------------- */
+
+		/* First reset DTR & RTS; then set them */
+		fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
+		fepcmd(ch, SETMODEM, mval, 0, 0, 1);
+
+	}
+
+	if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) 
+	{
+		ch->fepstartc = ch->startc;
+		ch->fepstopc = ch->stopc;
+
+		/* ------------------------------------------------------------
+			The XON / XOFF characters have changed; propogate these
+			changes to the card.	
+		--------------------------------------------------------------- */
+
+		fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+	}
+
+	if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) 
+	{
+		ch->fepstartca = ch->startca;
+		ch->fepstopca = ch->stopca;
+
+		/* ---------------------------------------------------------------
+			Similar to the above, this time the auxilarly XON / XOFF 
+			characters have changed; propogate these changes to the card.
+		------------------------------------------------------------------ */
+
+		fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+	}
+
+} /* End epcaparam */
+
+/* --------------------- Begin receive_data  ----------------------- */
+
+static void receive_data(struct channel *ch)
+{ /* Begin receive_data */
+
+	unchar *rptr;
+	struct termios *ts = 0;
+	struct tty_struct *tty;
+	volatile struct board_chan *bc;
+	register int dataToRead, wrapgap, bytesAvailable;
+	register unsigned int tail, head;
+	unsigned int wrapmask;
+	int rc;
+
+
+	/* ---------------------------------------------------------------
+		This routine is called by doint when a receive data event 
+		has taken place.
+	------------------------------------------------------------------- */
+
+	globalwinon(ch);
+
+	if (ch->statusflags & RXSTOPPED)
+		return;
+
+	tty = ch->tty;
+	if (tty)
+		ts = tty->termios;
+
+	bc = ch->brdchan;
+
+	if (!bc) 
+	{
+		printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n");
+		return;
+	}
+
+	wrapmask = ch->rxbufsize - 1;
+
+	/* --------------------------------------------------------------------- 
+		Get the head and tail pointers to the receiver queue.  Wrap the 
+		head pointer if it has reached the end of the buffer.
+	------------------------------------------------------------------------ */
+
+	head = bc->rin;
+	head &= wrapmask;
+	tail = bc->rout & wrapmask;
+
+	bytesAvailable = (head - tail) & wrapmask;
+
+	if (bytesAvailable == 0)
+		return;
+
+	/* ------------------------------------------------------------------
+	   If CREAD bit is off or device not open, set TX tail to head
+	--------------------------------------------------------------------- */
+
+	if (!tty || !ts || !(ts->c_cflag & CREAD)) 
+	{
+		bc->rout = head;
+		return;
+	}
+
+	if (tty->flip.count == TTY_FLIPBUF_SIZE) 
+		return;
+
+	if (bc->orun) 
+	{
+		bc->orun = 0;
+		printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",MINOR(tty->device));
+	}
+
+	rxwinon(ch);
+	rptr = tty->flip.char_buf_ptr;
+	rc = tty->flip.count;
+
+	while (bytesAvailable > 0) 
+	{ /* Begin while there is data on the card */
+
+		wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
+
+		/* ---------------------------------------------------------------
+			Even if head has wrapped around only report the amount of
+			data to be equal to the size - tail.  Remember memcpy can't
+			automaticly wrap around the receive buffer.
+		----------------------------------------------------------------- */
+
+		dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
+
+		/* --------------------------------------------------------------
+		   Make sure we don't overflow the buffer
+		----------------------------------------------------------------- */
+
+		if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
+			dataToRead = TTY_FLIPBUF_SIZE - rc;
+
+		if (dataToRead == 0)
+			break;
+
+		/* ---------------------------------------------------------------
+			Move data read from our card into the line disciplines buffer
+			for translation if necessary.
+		------------------------------------------------------------------ */
+
+		if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr)
+			printk(KERN_ERR "<Error> - receive_data : memcpy failed\n");
+			
+		rc   += dataToRead;
+		rptr += dataToRead;
+		tail = (tail + dataToRead) & wrapmask;
+		bytesAvailable -= dataToRead;
+
+	} /* End while there is data on the card */
+
+
+	tty->flip.count = rc;
+	tty->flip.char_buf_ptr = rptr;
+	globalwinon(ch);
+	bc->rout = tail;
+
+	/* Must be called with global data */
+	tty_schedule_flip(ch->tty); 
+	return;
+
+} /* End receive_data */
+
+/* --------------------- Begin pc_ioctl  ----------------------- */
+
+static int pc_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{ /* Begin pc_ioctl */
+
+	digiflow_t dflow;
+	int retval, error;
+	unsigned long flags;
+	unsigned int mflag, mstat;
+	unsigned char startc, stopc;
+	volatile struct board_chan *bc;
+	struct channel *ch = (struct channel *) tty->driver_data;
+	
+	/* The control device has it's own set of commands */
+	if (tty->driver.subtype == SERIAL_TYPE_INFO) 
+	{ /* Begin if subtype is the control device */
+
+		switch (cmd) 
+		{ /* Begin switch cmd */
+
+			case DIGI_GETINFO:
+			{ /* Begin case DIGI_GETINFO */
+
+				struct digi_info di ;
+				int brd;
+
+				getUser(brd, (unsigned int *)arg);
+
+				if ((error = verify_area(VERIFY_WRITE, (char*)arg, sizeof(di))))
+				{
+					printk(KERN_ERR "DIGI_GETINFO : verify area size 0x%x failed\n",sizeof(di));
+					return(error);
+				}
+
+				if ((brd < 0) || (brd >= num_cards) || (num_cards == 0))
+					return (-ENODEV);
+
+				memset(&di, 0, sizeof(di));
+
+				di.board = brd ; 
+				di.status = boards[brd].status;
+				di.type = boards[brd].type ;
+				di.numports = boards[brd].numports ;
+				di.port = boards[brd].port ;
+				di.membase = boards[brd].membase ;
+
+				copy_to_user((char *)arg, &di, sizeof (di));
+				break;
+
+			} /* End case DIGI_GETINFO */
+
+			case DIGI_POLLER:
+			{ /* Begin case DIGI_POLLER */
+
+				int brd = arg & 0xff000000 >> 16 ; 
+				unsigned char state = arg & 0xff ; 
+
+				if ((brd < 0) || (brd >= num_cards))
+				{
+					printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n");
+					return (-ENODEV);
+				}
+
+				digi_poller_inhibited = state ;
+				break ; 
+
+			} /* End case DIGI_POLLER */
+
+			case DIGI_INIT:
+			{ /* Begin case DIGI_INIT */
+
+				/* ------------------------------------------------------------
+					This call is made by the apps to complete the initilization
+					of the board(s).  This routine is responsible for setting
+					the card to its initial state and setting the drivers control
+					fields to the sutianle settings for the card in question.
+				---------------------------------------------------------------- */
+			
+				int crd ; 
+				for (crd = 0; crd < num_cards; crd++) 
+					post_fep_init (crd);
+
+			 	break ; 
+
+			} /* End case DIGI_INIT */
+
+
+			default:
+				return -ENOIOCTLCMD;
+
+		} /* End switch cmd */
+		return (0) ;
+
+	} /* End if subtype is the control device */
+
+	if (ch)
+		bc = ch->brdchan;
+	else 
+	{
+		printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n");
+		return(-EINVAL);
+	}
+
+	save_flags(flags);
+
+	/* -------------------------------------------------------------------
+		For POSIX compliance we need to add more ioctls.  See tty_ioctl.c
+		in /usr/src/linux/drivers/char for a good example.  In particular 
+		think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
+	---------------------------------------------------------------------- */
+
+	switch (cmd) 
+	{ /* Begin switch cmd */
+
+		case TCGETS:
+			retval = verify_area(VERIFY_WRITE, (void *)arg,
+                              sizeof(struct termios));
+			
+			if (retval)
+				return(retval);
+
+			copy_to_user((struct termios *)arg, 
+			             tty->termios, sizeof(struct termios));
+			return(0);
+
+		case TCGETA:
+			return get_termio(tty, (struct termio *)arg);
+
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+
+			/* Setup an event to indicate when the transmit buffer empties */
+
+			setup_empty_event(tty,ch);		
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				digi_send_break(ch, HZ/4);    /* 1/4 second */
+			return 0;
+
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+
+			/* Setup an event to indicate when the transmit buffer empties */
+
+			setup_empty_event(tty,ch);		
+			tty_wait_until_sent(tty, 0);
+			digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+
+		case TIOCGSOFTCAR:
+
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			if (error)
+				return error;
+
+			putUser(C_CLOCAL(tty) ? 1 : 0,
+			            (unsigned long *) arg);
+			return 0;
+
+		case TIOCSSOFTCAR:
+			/*RONNIE PUT VERIFY_READ (See above) check here */
+		{
+			unsigned int value;
+
+			getUser(value, (unsigned int *)arg);
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (value ? CLOCAL : 0));
+			return 0;
+		}
+
+		case TIOCMODG:
+		case TIOCMGET:
+
+			mflag = 0;
+
+			cli();
+			globalwinon(ch);
+			mstat = bc->mstat;
+			memoff(ch);
+			restore_flags(flags);
+
+			if (mstat & ch->m_dtr)
+				mflag |= TIOCM_DTR;
+
+			if (mstat & ch->m_rts)
+				mflag |= TIOCM_RTS;
+
+			if (mstat & ch->m_cts)
+				mflag |= TIOCM_CTS;
+
+			if (mstat & ch->dsr)
+				mflag |= TIOCM_DSR;
+
+			if (mstat & ch->m_ri)
+				mflag |= TIOCM_RI;
+
+			if (mstat & ch->dcd)
+				mflag |= TIOCM_CD;
+
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+
+			if (error)
+				return error;
+
+			putUser(mflag, (unsigned long *) arg);
+
+			break;
+
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMODS:
+		case TIOCMSET:
+
+			getUser(mstat, (unsigned int *)arg);
+
+			mflag = 0;
+			if (mstat & TIOCM_DTR)
+				mflag |= ch->m_dtr;
+
+			if (mstat & TIOCM_RTS)
+				mflag |= ch->m_rts;
+
+			switch (cmd) 
+			{ /* Begin switch cmd */
+
+				case TIOCMODS:
+				case TIOCMSET:
+					ch->modemfake = ch->m_dtr|ch->m_rts;
+					ch->modem = mflag;
+					break;
+
+				case TIOCMBIS:
+					ch->modemfake |= mflag;
+					ch->modem |= mflag;
+					break;
+
+				case TIOCMBIC:
+					ch->modemfake |= mflag;
+					ch->modem &= ~mflag;
+					break;
+
+			} /* End switch cmd */
+
+			cli();
+			globalwinon(ch);
+
+			/*  --------------------------------------------------------------
+				The below routine generally sets up parity, baud, flow control 
+				issues, etc.... It effect both control flags and input flags.
+			------------------------------------------------------------------ */
+
+			epcaparam(tty,ch);
+			memoff(ch);
+			restore_flags(flags);
+			break;
+
+		case TIOCSDTR:
+			ch->omodem |= ch->m_dtr;
+			cli();
+			globalwinon(ch);
+			fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
+			memoff(ch);
+			restore_flags(flags);
+			break;
+
+		case TIOCCDTR:
+			ch->omodem &= ~ch->m_dtr;
+			cli();
+			globalwinon(ch);
+			fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
+			memoff(ch);
+			restore_flags(flags);
+			break;
+
+		case DIGI_GETA:
+			if ((error=
+				verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
+			{
+				printk(KERN_ERR "<Error> - Digi GETA failed\n");
+				return(error);
+			}
+
+			copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
+			break;
+
+		case DIGI_SETAW:
+		case DIGI_SETAF:
+			if ((cmd) == (DIGI_SETAW)) 
+			{
+				/* Setup an event to indicate when the transmit buffer empties */
+
+				setup_empty_event(tty,ch);		
+				tty_wait_until_sent(tty, 0);
+			}
+			else 
+			{
+				if (tty->ldisc.flush_buffer)
+					tty->ldisc.flush_buffer(tty);
+			}
+
+			/* Fall Thru */
+
+		case DIGI_SETA:
+			if ((error =
+				verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
+				return(error);
+
+			copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
+			
+			if (ch->digiext.digi_flags & DIGI_ALTPIN) 
+			{
+				ch->dcd = ch->m_dsr;
+				ch->dsr = ch->m_dcd;
+			} 
+			else 
+			{
+				ch->dcd = ch->m_dcd;
+				ch->dsr = ch->m_dsr;
+			}
+		
+			cli();
+			globalwinon(ch);
+
+			/* -----------------------------------------------------------------
+				The below routine generally sets up parity, baud, flow control 
+				issues, etc.... It effect both control flags and input flags.
+			------------------------------------------------------------------- */
+
+			epcaparam(tty,ch);
+			memoff(ch);
+			restore_flags(flags);
+			break;
+
+		case DIGI_GETFLOW:
+		case DIGI_GETAFLOW:
+			cli();	
+			globalwinon(ch);
+			if ((cmd) == (DIGI_GETFLOW)) 
+			{
+				dflow.startc = bc->startc;
+				dflow.stopc = bc->stopc;
+			}
+			else 
+			{
+				dflow.startc = bc->startca;
+				dflow.stopc = bc->stopca;
+			}
+			memoff(ch);
+			restore_flags(flags);
+
+			if ((error = verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
+				return(error);
+
+			copy_to_user((char*)arg, &dflow, sizeof(dflow));
+			break;
+
+		case DIGI_SETAFLOW:
+		case DIGI_SETFLOW:
+			if ((cmd) == (DIGI_SETFLOW)) 
+			{
+				startc = ch->startc;
+				stopc = ch->stopc;
+			} 
+			else 
+			{
+				startc = ch->startca;
+				stopc = ch->stopca;
+			}
+
+			if ((error = verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
+				return(error);
+
+			copy_from_user(&dflow, (char*)arg, sizeof(dflow));
+
+			if (dflow.startc != startc || dflow.stopc != stopc) 
+			{ /* Begin  if setflow toggled */
+				cli();
+				globalwinon(ch);
+
+				if ((cmd) == (DIGI_SETFLOW)) 
+				{
+					ch->fepstartc = ch->startc = dflow.startc;
+					ch->fepstopc = ch->stopc = dflow.stopc;
+					fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+				} 
+				else 
+				{
+					ch->fepstartca = ch->startca = dflow.startc;
+					ch->fepstopca  = ch->stopca = dflow.stopc;
+					fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+				}
+
+				if	(ch->statusflags & TXSTOPPED)
+					pc_start(tty);
+
+				memoff(ch);
+				restore_flags(flags);
+
+			} /* End if setflow toggled */
+			break;
+
+		default:
+			return -ENOIOCTLCMD;
+
+	} /* End switch cmd */
+
+	return 0;
+
+} /* End pc_ioctl */
+
+/* --------------------- Begin pc_set_termios  ----------------------- */
+
+static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{ /* Begin pc_set_termios */
+
+	struct channel *ch;
+	unsigned long flags;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if channel valid */
+
+		save_flags(flags);
+		cli();
+		globalwinon(ch);
+		epcaparam(tty, ch);
+		memoff(ch);
+
+		if ((old_termios->c_cflag & CRTSCTS) &&
+			 ((tty->termios->c_cflag & CRTSCTS) == 0))
+			tty->hw_stopped = 0;
+
+		if (!(old_termios->c_cflag & CLOCAL) &&
+			 (tty->termios->c_cflag & CLOCAL))
+			wake_up_interruptible(&ch->open_wait);
+
+		restore_flags(flags);
+
+	} /* End if channel valid */
+
+} /* End pc_set_termios */
+
+/* --------------------- Begin do_softint  ----------------------- */
+
+static void do_softint(void *private_)
+{ /* Begin do_softint */
+
+	struct channel *ch = (struct channel *) private_;
+	
+
+	/* Called in response to a modem change event */
+
+	if (ch && ch->magic == EPCA_MAGIC) 
+	{ /* Begin EPCA_MAGIC */
+
+		struct tty_struct *tty = ch->tty;
+
+		if (tty && tty->driver_data) 
+		{ 
+			if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) 
+			{ /* Begin if clear_bit */
+
+				tty_hangup(tty);
+				wake_up_interruptible(&ch->open_wait);
+				ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+
+			} /* End if clear_bit */
+		}
+
+	} /* End EPCA_MAGIC */
+
+} /* End do_softint */
+
+/* ------------------------------------------------------------
+	pc_stop and pc_start provide software flow control to the 
+	routine and the pc_ioctl routine.
+---------------------------------------------------------------- */
+
+/* --------------------- Begin pc_stop  ----------------------- */
+
+static void pc_stop(struct tty_struct *tty)
+{ /* Begin pc_stop */
+
+	struct channel *ch;
+	unsigned long flags;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if valid channel */
+
+		save_flags(flags); 
+		cli();
+
+		if ((ch->statusflags & TXSTOPPED) == 0) 
+		{ /* Begin if transmit stop requested */
+
+			globalwinon(ch);
+
+			/* STOP transmitting now !! */
+
+			fepcmd(ch, PAUSETX, 0, 0, 0, 0);
+
+			ch->statusflags |= TXSTOPPED;
+			memoff(ch);
+
+		} /* End if transmit stop requested */
+
+		restore_flags(flags);
+
+	} /* End if valid channel */
+
+} /* End pc_stop */
+
+/* --------------------- Begin pc_start  ----------------------- */
+
+static void pc_start(struct tty_struct *tty)
+{ /* Begin pc_start */
+
+	struct channel *ch;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if channel valid */
+
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		/* Just in case output was resumed because of a change in Digi-flow */
+		if (ch->statusflags & TXSTOPPED) 
+		{ /* Begin transmit resume requested */
+
+			volatile struct board_chan *bc;
+
+			globalwinon(ch);
+			bc = ch->brdchan;
+			if (ch->statusflags & LOWWAIT)
+				bc->ilow = 1;
+
+			/* Okay, you can start transmitting again... */
+
+			fepcmd(ch, RESUMETX, 0, 0, 0, 0);
+
+			ch->statusflags &= ~TXSTOPPED;
+			memoff(ch);
+
+		} /* End transmit resume requested */
+
+		restore_flags(flags);
+
+	} /* End if channel valid */
+
+} /* End pc_start */
+
+/* ------------------------------------------------------------------
+	The below routines pc_throttle and pc_unthrottle are used 
+	to slow (And resume) the receipt of data into the kernels
+	receive buffers.  The exact occurence of this depends on the
+	size of the kernels receive buffer and what the 'watermarks'
+	are set to for that buffer.  See the n_ttys.c file for more
+	details. 
+______________________________________________________________________ */
+/* --------------------- Begin throttle  ----------------------- */
+
+static void pc_throttle(struct tty_struct * tty)
+{ /* Begin pc_throttle */
+
+	struct channel *ch;
+	unsigned long flags;
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if channel valid */
+
+
+		save_flags(flags);
+		cli();
+
+		if ((ch->statusflags & RXSTOPPED) == 0)
+		{
+			globalwinon(ch);
+			fepcmd(ch, PAUSERX, 0, 0, 0, 0);
+
+			ch->statusflags |= RXSTOPPED;
+			memoff(ch);
+		}
+		restore_flags(flags);
+
+	} /* End if channel valid */
+
+} /* End pc_throttle */
+
+/* --------------------- Begin unthrottle  ----------------------- */
+
+static void pc_unthrottle(struct tty_struct *tty)
+{ /* Begin pc_unthrottle */
+
+	struct channel *ch;
+	unsigned long flags;
+	volatile struct board_chan *bc;
+
+
+	/* ---------------------------------------------------------
+		verifyChannel returns the channel from the tty struct
+		if it is valid.  This serves as a sanity check.
+	------------------------------------------------------------- */
+
+	if ((ch = verifyChannel(tty)) != NULL) 
+	{ /* Begin if channel valid */
+
+
+		/* Just in case output was resumed because of a change in Digi-flow */
+		save_flags(flags);
+		cli();
+
+		if (ch->statusflags & RXSTOPPED) 
+		{
+
+			globalwinon(ch);
+			bc = ch->brdchan;
+			fepcmd(ch, RESUMERX, 0, 0, 0, 0);
+
+			ch->statusflags &= ~RXSTOPPED;
+			memoff(ch);
+		}
+		restore_flags(flags);
+
+	} /* End if channel valid */
+
+} /* End pc_unthrottle */
+
+/* --------------------- Begin digi_send_break  ----------------------- */
+
+void digi_send_break(struct channel *ch, int msec)
+{ /* Begin digi_send_break */
+
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+
+	/* -------------------------------------------------------------------- 
+	   Maybe I should send an infinite break here, schedule() for
+	   msec amount of time, and then stop the break.  This way,
+	   the user can't screw up the FEP by causing digi_send_break()
+	   to be called (i.e. via an ioctl()) more than once in msec amount 
+	   of time.  Try this for now...
+	------------------------------------------------------------------------ */
+
+	fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
+	memoff(ch);
+
+	restore_flags(flags);
+
+} /* End digi_send_break */
+
+/* --------------------- Begin setup_empty_event  ----------------------- */
+
+static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
+{ /* Begin setup_empty_event */
+
+	volatile struct board_chan *bc = ch->brdchan;
+	unsigned long int flags;
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+	ch->statusflags |= EMPTYWAIT;
+	
+	/* ------------------------------------------------------------------
+		When set the iempty flag request a event to be generated when the 
+		transmit buffer is empty (If there is no BREAK in progress).
+	--------------------------------------------------------------------- */
+
+	bc->iempty = 1;
+	memoff(ch);
+	restore_flags(flags);
+
+} /* End setup_empty_event */
+
+/* --------------------- Begin get_termio ----------------------- */
+
+static int get_termio(struct tty_struct * tty, struct termio * termio)
+{ /* Begin get_termio */
+	int error;
+
+	error = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
+	if (error)
+		return error;
+
+	kernel_termios_to_user_termio(termio, tty->termios);
+
+	return 0;
+} /* End get_termio */
+/* ---------------------- Begin epca_setup  -------------------------- */
+void epca_setup(char *str, int *ints)
+{ /* Begin epca_setup */
+
+	struct board_info board;
+	int               index, loop, last;
+	char              *temp, *t2;
+	unsigned          len;
+
+	/* ----------------------------------------------------------------------
+		If this routine looks a little strange it is because it is only called
+		if a LILO append command is given to boot the kernel with parameters.  
+		In this way, we can provide the user a method of changing his board
+		configuration without rebuilding the kernel.
+	----------------------------------------------------------------------- */
+	if (!liloconfig) 
+		liloconfig = 1; 
+
+	memset(&board, 0, sizeof(board));
+
+	/* Assume the data is int first, later we can change it */
+	/* I think that array position 0 of ints holds the number of args */
+	for (last = 0, index = 1; index <= ints[0]; index++)
+		switch(index)
+		{ /* Begin parse switch */
+
+			case 1:
+				board.status = ints[index];
+				
+				/* ---------------------------------------------------------
+					We check for 2 (As opposed to 1; because 2 is a flag
+					instructing the driver to ignore epcaconfig.)  For this
+					reason we check for 2.
+				------------------------------------------------------------ */ 
+				if (board.status == 2)
+				{ /* Begin ignore epcaconfig as well as lilo cmd line */
+					nbdevs = 0;
+					num_cards = 0;
+					return;
+				} /* End ignore epcaconfig as well as lilo cmd line */
+	
+				if (board.status > 2)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_BOARD_STATUS;
+					return;
+				}
+				last = index;
+				break;
+
+			case 2:
+				board.type = ints[index];
+				if (board.type >= PCIXEM) 
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_BOARD_TYPE;
+					return;
+				}
+				last = index;
+				break;
+
+			case 3:
+				board.altpin = ints[index];
+				if (board.altpin > 1)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_ALTPIN;
+					return;
+				}
+				last = index;
+				break;
+
+			case 4:
+				board.numports = ints[index];
+				if ((board.numports < 2) || (board.numports > 256))
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_NUM_PORTS;
+					return;
+				}
+				nbdevs += board.numports;
+				last = index;
+				break;
+
+			case 5:
+				board.port = (unsigned char *)ints[index];
+				if (board.port <= 0)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_PORT_BASE;
+					return;
+				}
+				last = index;
+				break;
+
+			case 6:
+				board.membase = (unsigned char *)ints[index];
+				if (board.membase <= 0)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_MEM_BASE;
+					return;
+				}
+				last = index;
+				break;
+
+			default:
+				printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
+				return;
+
+		} /* End parse switch */
+
+	while (str && *str) 
+	{ /* Begin while there is a string arg */
+
+		/* find the next comma or terminator */
+		temp = str;
+
+		/* While string is not null, and a comma hasn't been found */
+		while (*temp && (*temp != ','))
+			temp++;
+
+		if (!*temp)
+			temp = NULL;
+		else
+			*temp++ = 0;
+
+		/* Set index to the number of args + 1 */
+		index = last + 1;
+
+		switch(index)
+		{
+			case 1:
+				len = strlen(str);
+				if (strncmp("Disable", str, len) == 0) 
+					board.status = 0;
+				else
+				if (strncmp("Enable", str, len) == 0)
+					board.status = 1;
+				else
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_BOARD_STATUS;
+					return;
+				}
+				last = index;
+				break;
+
+			case 2:
+
+				for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
+					if (strcmp(board_desc[loop], str) == 0)
+						break;
+
+
+				/* ---------------------------------------------------------------
+					If the index incremented above refers to a legitamate board 
+					type set it here. 
+				------------------------------------------------------------------*/
+
+				if (index < EPCA_NUM_TYPES) 
+					board.type = loop;
+				else
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_BOARD_TYPE;
+					return;
+				}
+				last = index;
+				break;
+
+			case 3:
+				len = strlen(str);
+				if (strncmp("Disable", str, len) == 0) 
+					board.altpin = 0;
+				else
+				if (strncmp("Enable", str, len) == 0)
+					board.altpin = 1;
+				else
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_ALTPIN;
+					return;
+				}
+				last = index;
+				break;
+
+			case 4:
+				t2 = str;
+				while (isdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_NUM_PORTS;
+					return;
+				}
+
+				/* ------------------------------------------------------------
+					There is not a man page for simple_strtoul but the code can be 
+					found in vsprintf.c.  The first argument is the string to 
+					translate (To an unsigned long obviously),  the second argument
+					can be the address of any character variable or a NULL.  If a
+					variable is given, the end pointer of the string will be stored 
+					in that variable; if a NULL is given the the end pointer will 
+					not be returned.  The last argument is the base to use.  If 
+					a 0 is indicated, the routine will attempt to determine the 
+					proper base by looking at the values prefix (A '0' for octal,
+					a 'x' for hex, etc ...  If a value is given it will use that 
+					value as the base. 
+				---------------------------------------------------------------- */ 
+				board.numports = simple_strtoul(str, NULL, 0);
+				nbdevs += board.numports;
+				last = index;
+				break;
+
+			case 5:
+				t2 = str;
+				while (isxdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_PORT_BASE;
+					return;
+				}
+
+				board.port = (unsigned char *)simple_strtoul(str, NULL, 16);
+				last = index;
+				break;
+
+			case 6:
+				t2 = str;
+				while (isxdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str);
+					invalid_lilo_config = 1;
+					setup_error_code |= INVALID_MEM_BASE;
+					return;
+				}
+
+				board.membase = (unsigned char *)simple_strtoul(str, NULL, 16);
+				last = index;
+				break;
+
+			default:
+				printk(KERN_ERR "PC/Xx: Too many string parms\n");
+				return;
+		}
+		str = temp;
+
+	} /* End while there is a string arg */
+
+
+	if (last < 6)  
+	{
+		printk(KERN_ERR "PC/Xx: Insufficient parms specified\n");
+		return;
+	}
+ 
+	/* I should REALLY validate the stuff here */
+
+	/* Copies our local copy of board into boards */
+	memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+
+
+	/* Does this get called once per lilo arg are what ? */
+
+	printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", 
+		num_cards, board_desc[board.type], 
+		board.numports, (int)board.port, (unsigned int) board.membase);
+
+	num_cards++;
+
+} /* End epca_setup */
+
+
+
+#ifdef ENABLE_PCI
+/* --------------------- Begin get_PCI_configuration  ---------------------- */
+
+int get_PCI_configuration(char bus, char device_fn, 
+                          unsigned int *base_addr0, unsigned int *base_addr1,
+                          unsigned int *base_addr2, unsigned int *base_addr3,
+                          unsigned int *base_addr4, unsigned int *base_addr5)
+{ /* Begin get_PCI_configuration */
+
+	int	error;
+
+	error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
+	                                  base_addr0);
+
+	error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1,
+                                      base_addr1);
+
+	error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2,
+                                      base_addr2);
+
+	error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_3,
+                                      base_addr3);
+
+	error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_4,
+                                      base_addr4);
+
+	error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_5,
+                                      base_addr5);
+
+	/* ------------------------------------------------------------------------
+			 NOTE - The code below mask out either the 2 or 4 bits dependant on the
+				space being addressed. (base_addr value reflecting io space, have their
+				first 2 bits mask out, while base_addr value reflecting mem space, have
+				their first 4 bits mask out.)  These bits are flag bits and should always
+				be 0 when used as an address.
+	---------------------------------------------------------------------------- */
+
+	if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
+		(*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK;
+	else
+		(*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	if (error) 
+	{
+		printk(KERN_ERR "<Error> - DIGI PCI error: board not initializing due to error\n");
+		return(0);
+	}
+	return(1);
+} /* End get_PCI_configuration */
+
+/* ------------------------ Begin init_PCI  --------------------------- */
+
+int init_PCI(int boards_found)
+{ /* Begin init_PCI */
+
+	unsigned char	bus, device_fn;
+	int i, pci_count = 0;
+	unsigned int base_addr0, base_addr1, base_addr2,
+                base_addr3, base_addr4, base_addr5;
+
+	base_addr0 = base_addr1 = base_addr2 = 0;
+	base_addr3 = base_addr4 = base_addr5 = 0;
+
+	for(i = 0; i < (MAXBOARDS - boards_found); i++) 
+	{ /* Begin for each POSSIBLE remaining board */
+
+		if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XR,
+			i, &bus, &device_fn)) 
+		{ /* Begin found XR */
+			if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+                                                   &base_addr2, &base_addr3,
+                                                   &base_addr4, &base_addr5))
+			{ /* Store a PCI/XR into the boards structure */
+
+
+				boards[boards_found + pci_count].status   = ENABLED;
+				boards[boards_found + pci_count].type     = PCIXR;
+
+				boards[boards_found + pci_count].numports = 0x0;
+
+				boards[boards_found + pci_count].port     = (unsigned char *)((char *)base_addr0 + PCI_IO_OFFSET);
+				/* Most cards use base_addr0, but some use base_addr2 */
+				boards[boards_found + pci_count].membase  = (unsigned char *)base_addr0;
+
+				if (base_addr0 >= 0x100000)
+				{
+					/* ------------------------------------------------------------
+						Standard physical addresses are valid to the kernel as long 
+						as they aren't above RAM. Higher addresses (Such as are 
+						typical of a PCI system) need to be mapped in with the 
+						ioremap command.  For boards using such high addresses the
+						driver will store both addresses.  One address (The physical)
+						will be held for the apps use (And mmap) and the other (The
+						ioremapped address) will be used in the kernel.
+ 
+					---------------------------------------------------------------- */
+					boards[boards_found + pci_count].re_map_port     = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+					boards[boards_found + pci_count].re_map_membase  = ioremap(base_addr0, 0x200000);
+				}
+
+				pci_count++;
+
+				/* --------------------------------------------------------------
+					I don't know what the below does, but the hardware guys say
+					its required on everything except PLX (In this case XRJ).
+				---------------------------------------------------------------- */
+				pcibios_write_config_byte(bus, device_fn, 0x40, 0);  
+				pcibios_write_config_byte(bus, device_fn, 0x46, 0);  
+
+			} /* End store a PCI/XR into the board structure */
+				
+		} /* End found XR */
+
+		if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XEM,
+			i, &bus, &device_fn)) 
+		{ /* Begin found XEM */
+
+			if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+			                                          &base_addr2, &base_addr3,
+			                                          &base_addr4, &base_addr5))
+			{ /* Begin store a PCI/XEM into the boards structure */
+
+				boards[boards_found + pci_count].status   = ENABLED;
+				boards[boards_found + pci_count].type     = PCIXEM;
+
+				boards[boards_found + pci_count].numports = 0x0;
+				boards[boards_found + pci_count].port     = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+				/* Most cards use base_addr0, but some use base_addr2 */
+				boards[boards_found + pci_count].membase  = (unsigned char *)base_addr0;
+
+				if (base_addr0 >= 0x100000)
+				{
+					/* ------------------------------------------------------------
+						Standard physical addresses are valid to the kernel as long 
+						as they aren't above RAM. Higher addresses (Such as are 
+						typical of a PCI system) need to be mapped in with the 
+						ioremap command.  For boards using such high addresses the
+						driver will store both addresses.  One address (The physical)
+						will be held for the apps use (And mmap) and the other (The
+						vremapped address) will be used in the kernel.
+ 
+					---------------------------------------------------------------- */
+					boards[boards_found + pci_count].re_map_port     = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+					boards[boards_found + pci_count].re_map_membase  = ioremap(base_addr0, 0x200000);
+				}
+
+				pci_count++;
+				/* --------------------------------------------------------------
+					I don't know what the below does, but the hardware guys say
+					its required on everything except PLX (In this case XRJ).
+				---------------------------------------------------------------- */
+				pcibios_write_config_byte(bus, device_fn, 0x40, 0);  
+				pcibios_write_config_byte(bus, device_fn, 0x46, 0);  
+
+			} /* End store a PCI/XEM into the boards structure */
+
+		} /* End found XEM */
+
+
+		if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_CX,
+		                         i, &bus, &device_fn)) 
+		{ /* Begin found CX */
+
+			if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+			                                          &base_addr2, &base_addr3,
+			                                          &base_addr4, &base_addr5))
+			{ /* Begin store a PCI/CX into the boards structure */
+
+				boards[boards_found + pci_count].status   = ENABLED;
+				boards[boards_found + pci_count].type     = PCICX;
+
+				boards[boards_found + pci_count].numports = 0x0;
+				boards[boards_found + pci_count].port     = (char *)((char *)base_addr0 + PCI_IO_OFFSET);
+				/* Most cards use base_addr0, but some use base_addr2 */
+				boards[boards_found + pci_count].membase  = (unsigned char *)base_addr0;
+
+				if (base_addr0 >= 0x100000)
+				{
+					/* ------------------------------------------------------------
+						Standard physical addresses are valid to the kernel as long 
+						as they aren't above RAM. Higher addresses (Such as are 
+						typical of a PCI system) need to be mapped in with the 
+						ioremap command.  For boards using such high addresses the
+						driver will store both addresses.  One address (The physical)
+						will be held for the apps use (And mmap) and the other (The
+						vremapped address) will be used in the kernel.
+ 
+					---------------------------------------------------------------- */
+					boards[boards_found + pci_count].re_map_port     = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000);
+					boards[boards_found + pci_count].re_map_membase  = ioremap(base_addr0, 0x200000);
+				}
+
+				pci_count++;
+				/* --------------------------------------------------------------
+					I don't know what the below does, but the hardware guys say
+					its required on everything except PLX (In this case XRJ).
+				---------------------------------------------------------------- */
+				pcibios_write_config_byte(bus, device_fn, 0x40, 0);  
+				pcibios_write_config_byte(bus, device_fn, 0x46, 0);  
+
+			} /* End store a PCI/CX into the boards structure */
+
+		} /* End found CX */
+
+		if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XRJ,
+		                         i, &bus, &device_fn)) 
+		{ /* Begin found XRJ */
+
+			if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1,
+			                                          &base_addr2, &base_addr3,
+			                                          &base_addr4, &base_addr5))
+			{ /* Begin store a PCI/XRJ into the boards structure */
+
+				boards[boards_found + pci_count].status   = ENABLED;
+				boards[boards_found + pci_count].type     = PCIXRJ;
+
+				boards[boards_found + pci_count].numports = 0x0;
+				boards[boards_found + pci_count].port     = (unsigned char *)(base_addr2 + PCI_IO_OFFSET);
+				/* Most cards use base_addr0, but some use base_addr2 */
+				boards[boards_found + pci_count].membase  = (unsigned char *)base_addr2;
+
+				if (base_addr2 >= 0x100000)
+				{
+					/* ------------------------------------------------------------
+						Standard physical addresses are valid to the kernel as long 
+						as they aren't above RAM. Higher addresses (Such as are 
+						typical of a PCI system) need to be mapped in with the 
+						ioremap command.  For boards using such high addresses the
+						driver will store both addresses.  One address (The physical)
+						will be held for the apps use (And mmap) and the other (The
+						vremapped address) will be used in the kernel.
+ 
+					---------------------------------------------------------------- */
+					boards[boards_found + pci_count].re_map_port     = ioremap((base_addr2 + PCI_IO_OFFSET),0x200000);
+					boards[boards_found + pci_count].re_map_membase  = ioremap(base_addr2, 0x200000);
+				}
+
+				pci_count++;
+
+			} /* End store a PCI/XRJ into the boards structure */
+
+		} /* End found XRJ */
+
+	} /* End for each POSSIBLE remaining board */
+
+	return(pci_count);
+
+} /* End init_PCI */
+
+#endif /* ENABLE_PCI */
+
+
diff -u --recursive --new-file v2.1.36/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.36/linux/drivers/char/esp.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/esp.c	Mon May 12 10:35:40 1997
@@ -689,7 +689,7 @@
 	if (!tty)
 		return;
 
-	if (clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
+	if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) {
 		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 		    tty->ldisc.write_wakeup)
 			(tty->ldisc.write_wakeup)(tty);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v2.1.36/linux/drivers/char/fbmem.c	Fri Apr  4 08:52:19 1997
+++ linux/drivers/char/fbmem.c	Mon May 12 10:35:40 1997
@@ -16,6 +16,7 @@
 #include <linux/malloc.h>
 #include <linux/mman.h>
 #include <linux/tty.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -300,8 +301,8 @@
 	return 0;
 }
 
-void
-fbmem_init(void)
+__initfunc(void
+fbmem_init(void))
 {
 	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
 		printk("unable to get major %d for fb devs\n", FB_MAJOR);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c
--- v2.1.36/linux/drivers/char/ftape/kernel-interface.c	Fri Apr  4 08:52:19 1997
+++ linux/drivers/char/ftape/kernel-interface.c	Mon May 12 10:35:40 1997
@@ -29,6 +29,7 @@
 #include <linux/signal.h>
 #include <linux/major.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 #include <linux/ftape.h>
 #include <asm/dma.h>
 
@@ -120,7 +121,7 @@
 #define ftape_init init_module
 #endif
 
-int ftape_init(void)
+__initfunc(int ftape_init(void))
 {
 	int n;
 	int order;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.1.36/linux/drivers/char/istallion.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/istallion.c	Mon May 12 10:35:40 1997
@@ -1005,7 +1005,7 @@
 	set_bit(ST_GETSIGS, &portp->state);
 	if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0)
 		return(rc);
-	if (clear_bit(ST_GETSIGS, &portp->state))
+	if (test_and_clear_bit(ST_GETSIGS, &portp->state))
 		portp->sigs = stli_mktiocm(portp->asig.sigvalue);
 	stli_mkasysigs(&portp->asig, 1, 1);
 	if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0)
diff -u --recursive --new-file v2.1.36/linux/drivers/char/keyb_m68k.c linux/drivers/char/keyb_m68k.c
--- v2.1.36/linux/drivers/char/keyb_m68k.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/keyb_m68k.c	Mon May 12 17:39:50 1997
@@ -205,7 +205,7 @@
         keycode &= 0x7f;
 	if (up_flag) {
 		rep = 0;
- 		if(!clear_bit(keycode, key_down)) {
+ 		if(!test_and_clear_bit(keycode, key_down)) {
 		    /* unexpected, but this can happen:
 		       maybe this was a key release for a FOCUS 9000
 		       PF key; if we want to see it, we have to clear
@@ -216,7 +216,7 @@
 #endif
 		}
 	} else
- 		rep = set_bit(keycode, key_down);
+ 		rep = test_and_set_bit(keycode, key_down);
 
 	if (raw_mode)
 	        return;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.1.36/linux/drivers/char/keyboard.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/keyboard.c	Mon May 12 10:35:40 1997
@@ -501,7 +501,7 @@
 
 	if (up_flag) {
 		rep = 0;
- 		if(!clear_bit(keycode, key_down)) {
+		if(!test_and_clear_bit(keycode, key_down)) {
 		    /* unexpected, but this can happen:
 		       maybe this was a key release for a FOCUS 9000
 		       PF key; if we want to see it, we have to clear
@@ -510,7 +510,7 @@
 		      up_flag = 0;
 		}
 	} else
- 		rep = set_bit(keycode, key_down);
+ 		rep = test_and_set_bit(keycode, key_down);
 
 	if (kbd->kbdmode == VC_MEDIUMRAW) {
 		/* soon keycodes will require more than one byte */
diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.36/linux/drivers/char/lp.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/lp.c	Mon May 12 10:35:40 1997
@@ -631,7 +631,7 @@
 
 static int parport_ptr = 0;
 
-void lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
 {
 	/* Ugh. */
 	if (!strncmp(str, "parport", 7)) {
diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v2.1.36/linux/drivers/char/lp_intern.c	Fri Dec 20 01:20:00 1996
+++ linux/drivers/char/lp_intern.c	Mon May 12 10:35:40 1997
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
 #ifdef CONFIG_AMIGA
@@ -33,7 +34,6 @@
 #endif
 #include <linux/lp_intern.h>
 
-static int my_inter = 0;
 static int minor = -1;
 
 static void lp_int_out(int, int);
@@ -126,24 +126,18 @@
     }
 }
 
-static int lp_int_my_interrupt(int dev)
-{
-  return my_inter;
-}
-
 static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp)
 {
-  my_inter = 1;
-  lp_interrupt(irq, data, fp);
-  my_inter = 0;
+  lp_interrupt(minor);
 }
 
-static void lp_int_open(void)
+static int lp_int_open(int dev)
 {
   MOD_INC_USE_COUNT;
+  return 0;
 }
 
-static void lp_int_release(void)
+static void lp_int_release(int dev)
 {
   MOD_DEC_USE_COUNT;
 }
@@ -155,7 +149,7 @@
 	lp_int_busy,
 	lp_int_pout,
 	lp_int_online,
-	lp_int_my_interrupt,
+	0,
 	NULL,				/* ioctl */
 	lp_int_open,
 	lp_int_release,
@@ -167,7 +161,7 @@
 	NULL,
 };
 
-int lp_internal_init(void)
+__initfunc(int lp_internal_init(void))
 {
 #ifdef CONFIG_AMIGA
   if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.1.36/linux/drivers/char/lp_m68k.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/lp_m68k.c	Mon May 12 10:35:40 1997
@@ -41,6 +41,7 @@
 #include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/init.h>
 #include <asm/irq.h>
 #ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
@@ -465,7 +466,7 @@
 EXPORT_SYMBOL(register_parallel);
 EXPORT_SYMBOL(unregister_parallel);
 
-int lp_init(void)
+__initfunc(int lp_init(void))
 {
 	extern char m68k_debug_device[];
 
@@ -498,7 +499,7 @@
 /*
  * Currently we do not accept any lp-parameters, but that may change.
  */
-void	lp_setup(char *str, int *ints)
+__initfunc(void lp_setup(char *str, int *ints))
 {	
 }
 
diff -u --recursive --new-file v2.1.36/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.36/linux/drivers/char/mem.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/mem.c	Mon May 12 10:35:40 1997
@@ -139,7 +139,8 @@
 		else
 			tmp = count;
 		read = tmp;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+		/* we don't have page 0 mapped on sparc and m68k.. */
 		while (p < PAGE_SIZE && tmp > 0) {
 			put_user(0,buf);
 			buf++;
@@ -172,7 +173,8 @@
 	if (count > (unsigned long) high_memory - p)
 		count = (unsigned long) high_memory - p;
 	written = 0;
-#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+#if defined(__sparc__) || defined(__mc68000__)
+	/* we don't have page 0 mapped on sparc and m68k.. */
 	while (p < PAGE_SIZE && count > 0) {
 		/* Hmm. Do something? */
 		buf++;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.36/linux/drivers/char/misc.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/misc.c	Mon May 12 10:35:40 1997
@@ -73,6 +73,7 @@
 extern void wdt_init(void);
 extern void pcwatchdog_init(void);
 extern int rtc_init(void);
+extern int dsp56k_init(void);
 
 #ifdef CONFIG_PROC_FS
 static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -234,6 +235,9 @@
 #endif
 #ifdef CONFIG_RTC
 	rtc_init();
+#endif
+#ifdef CONFIG_ATARI_DSP56K
+	dsp56k_init();
 #endif
 #endif /* !MODULE */
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
diff -u --recursive --new-file v2.1.36/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v2.1.36/linux/drivers/char/msbusmouse.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/msbusmouse.c	Mon May 12 10:35:40 1997
@@ -51,7 +51,7 @@
 static struct mouse_status mouse;
 static int mouse_irq = MOUSE_IRQ;
 
-void msmouse_setup(char *str, int *ints)
+__initfunc(void msmouse_setup(char *str, int *ints))
 {
 	if (ints[0] > 0)
 		mouse_irq=ints[1];
diff -u --recursive --new-file v2.1.36/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.36/linux/drivers/char/n_tty.c	Mon Apr 14 16:28:11 1997
+++ linux/drivers/char/n_tty.c	Mon May 12 10:35:40 1997
@@ -78,7 +78,7 @@
 		return;
 
 	if (tty->driver.unthrottle &&
-	    clear_bit(TTY_THROTTLED, &tty->flags))
+	    test_and_clear_bit(TTY_THROTTLED, &tty->flags))
 		tty->driver.unthrottle(tty);
 	if (tty->link->packet) {
 		tty->ctrl_status |= TIOCPKT_FLUSHREAD;
@@ -598,7 +598,7 @@
 
 	if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
 	    tty->driver.throttle &&
-	    !set_bit(TTY_THROTTLED, &tty->flags))
+	    !test_and_set_bit(TTY_THROTTLED, &tty->flags))
 		tty->driver.throttle(tty);
 }
 
@@ -874,7 +874,7 @@
 				if (!tty->read_cnt) {
 					break;
 				}
-				eol = clear_bit(tty->read_tail,
+				eol = test_and_clear_bit(tty->read_tail,
 						&tty->read_flags);
 				c = tty->read_buf[tty->read_tail];
 				tty->read_tail = ((tty->read_tail+1) &
@@ -904,7 +904,7 @@
 		   low-level driver know. */
 		if (tty->driver.unthrottle &&
 		    (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
-		    && clear_bit(TTY_THROTTLED, &tty->flags))
+		    && test_and_clear_bit(TTY_THROTTLED, &tty->flags))
 			tty->driver.unthrottle(tty);
 
 		if (b - buf >= minimum || !nr)
@@ -923,7 +923,7 @@
 	size = b - buf;
 	if (size && nr)
 	        clear_bit(TTY_PUSH, &tty->flags);
-        if (!size && clear_bit(TTY_PUSH, &tty->flags))
+        if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags))
                 goto do_it_again;
 	if (!size && !retval)
 	        clear_bit(TTY_PUSH, &tty->flags);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.1.36/linux/drivers/char/pcxx.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/pcxx.c	Mon May 12 10:35:40 1997
@@ -895,7 +895,7 @@
  * Driver setup function when linked into the kernel to optionally parse multible
  * "digi="-lines and initialize the driver at boot time. No probing.
  */
-void pcxx_setup(char *str, int *ints)
+__initfunc(void pcxx_setup(char *str, int *ints))
 {
 
 	struct board_info board;
@@ -2358,7 +2358,7 @@
 	if(info && info->magic == PCXX_MAGIC) {
 		struct tty_struct *tty = info->tty;
 		if (tty && tty->driver_data) {
-			if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
+			if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
 				tty_hangup(tty);
 				wake_up_interruptible(&info->open_wait);
 				info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.1.36/linux/drivers/char/random.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/random.c	Mon May 12 10:35:40 1997
@@ -1,7 +1,7 @@
 /*
  * random.c -- A strong random number generator
  *
- * Version 1.01, last modified 13-Feb-97
+ * Version 1.02, last modified 15-Apr-97
  * 
  * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997.  All rights reserved.
  *
@@ -839,6 +839,18 @@
     digest[ 4 ] += E;
     }
 
+#undef ROTL
+#undef f1
+#undef f2
+#undef f3
+#undef f4
+#undef K1	
+#undef K2
+#undef K3	
+#undef K4	
+#undef expand
+#undef subRound
+	
 #else
 #define HASH_BUFFER_SIZE 4
 #define HASH_TRANSFORM MD5Transform
@@ -1324,22 +1336,90 @@
  * attacks which rely on guessing the initial TCP sequence number.
  * This algorithm was suggested by Steve Bellovin.
  */
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+#define ROTL(n,X)  ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) \
+  {(a) += F ((b), (c), (d)) + (x); \
+   (a) = ROTL ((s), (a));}
+#define GG(a, b, c, d, x, s) \
+  {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
+   (a) = ROTL ((s), (a));}
+#define HH(a, b, c, d, x, s) \
+  {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
+   (a) = ROTL ((s), (a));}
+
+/*
+ * Basic cut-down MD4 transform
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 in[8])
+{
+	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	FF (a, b, c, d, in[ 0],  3);
+	FF (d, a, b, c, in[ 1],  7);
+	FF (c, d, a, b, in[ 2], 11);
+	FF (b, c, d, a, in[ 3], 19);
+	FF (a, b, c, d, in[ 4],  3);
+	FF (d, a, b, c, in[ 5],  7);
+	FF (c, d, a, b, in[ 6], 11);
+	FF (b, c, d, a, in[ 7], 19);
+
+	/* Round 2 */
+	GG (a, b, c, d, in[ 0],  3);
+	GG (d, a, b, c, in[ 4],  5);
+	GG (a, b, c, d, in[ 1],  9);
+	GG (d, a, b, c, in[ 5], 13);
+	GG (a, b, c, d, in[ 2],  3);
+	GG (d, a, b, c, in[ 6],  5);
+	GG (a, b, c, d, in[ 3],  9);
+	GG (d, a, b, c, in[ 7], 13);
+
+	/* Round 3 */
+	HH (a, b, c, d, in[ 0],  3);
+	HH (c, d, a, b, in[ 4],  9);
+	HH (a, b, c, d, in[ 2], 11);
+	HH (c, d, a, b, in[ 6], 15);
+	HH (a, b, c, d, in[ 1],  3);
+	HH (c, d, a, b, in[ 5],  9);
+	HH (a, b, c, d, in[ 3], 11);
+	HH (c, d, a, b, in[ 7], 15);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#define REKEY_INTERVAL	300
+
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
-	static int	is_init = 0;
-	static __u32	secret[16];
+	static __u32	rekey_time = 0;
+	static __u32	secret[12];
+	static char	count = 0;
 	struct timeval 	tv;
-	__u32 		tmp[16];
+	__u32 		tmp[12];
 	__u32		seq;
 
 	/*
-	 * Pick a random secret the first time we open a TCP
-	 * connection.
+	 * Pick a random secret every REKEY_INTERVAL seconds
 	 */
-	if (is_init == 0) {
+	do_gettimeofday(&tv);
+	if (!rekey_time ||
+	    (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
 		get_random_bytes(&secret, sizeof(secret));
-		is_init = 1;
+		rekey_time = tv.tv_sec;
+		count++;
 	}
 
 	memcpy(tmp, secret, sizeof(tmp));
@@ -1350,7 +1430,7 @@
 	tmp[8]=saddr;
 	tmp[9]=daddr;
 	tmp[10]=(sport << 16) + dport;
-	HASH_TRANSFORM(tmp, tmp);
+	halfMD4Transform(tmp, tmp+4);
 	
 	/*
 	 *	As close as possible to RFC 793, which
@@ -1359,8 +1439,8 @@
 	 *	For 10MB/s ethernet, a 1MHz clock is appropriate.
 	 *	That's funny, Linux has one built in!  Use it!
 	 */
-	do_gettimeofday(&tv);
-	seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000;
+	seq = (tmp[1]&0xFFFFFF) + (tv.tv_usec+tv.tv_sec*1000000) +
+		(count << 24);
 #if 0
 	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
 	       saddr, daddr, sport, dport, seq);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.1.36/linux/drivers/char/riscom8.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/riscom8.c	Mon May 12 10:35:40 1997
@@ -1711,7 +1711,7 @@
 	if(!(tty = port->tty)) 
 		return;
 
-	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
 		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 		    tty->ldisc.write_wakeup)
 			(tty->ldisc.write_wakeup)(tty);
@@ -1821,7 +1821,7 @@
  * addresses in this case.
  *
  */ 
-void riscom8_setup(char *str, int * ints)
+__initfunc(void riscom8_setup(char *str, int * ints))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.36/linux/drivers/char/serial.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/serial.c	Mon May 12 10:35:40 1997
@@ -899,7 +899,7 @@
 	if (!tty)
 		return;
 
-	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
 		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 		    tty->ldisc.write_wakeup)
 			(tty->ldisc.write_wakeup)(tty);
diff -u --recursive --new-file v2.1.36/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.1.36/linux/drivers/char/tga.c	Mon Apr 14 16:28:11 1997
+++ linux/drivers/char/tga.c	Mon May 12 10:35:40 1997
@@ -26,6 +26,7 @@
 #include <linux/ioport.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -140,35 +141,35 @@
 unsigned long tga_regs_base;
 unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride;
 
-static unsigned int fb_offset_presets[4] = {
+static unsigned int fb_offset_presets[4] __initdata = {
 	TGA_8PLANE_FB_OFFSET,
 	TGA_24PLANE_FB_OFFSET,
 	0xffffffff,
 	TGA_24PLUSZ_FB_OFFSET
 };
 
-static unsigned int deep_presets[4] = {
+static unsigned int deep_presets[4] __initdata = {
   0x00014000,
   0x0001440d,
   0xffffffff,
   0x0001441d
 };
 
-static unsigned int rasterop_presets[4] = {
+static unsigned int rasterop_presets[4] __initdata = {
   0x00000003,
   0x00000303,
   0xffffffff,
   0x00000303
 };
 
-static unsigned int mode_presets[4] = {
+static unsigned int mode_presets[4] __initdata = {
   0x00002000,
   0x00002300,
   0xffffffff,
   0x00002300
 };
 
-static unsigned int base_addr_presets[4] = {
+static unsigned int base_addr_presets[4] __initdata = {
   0x00000000,
   0x00000001,
   0xffffffff,
@@ -304,8 +305,8 @@
   restore_flags(flags);
 }
 
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
 {
         can_do_color = 1;
 
@@ -323,8 +324,8 @@
 	return kmem_start;
 }
 
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
 {
 }
 
@@ -447,8 +448,8 @@
  * when TGA console is configured, at the end of the probing code,
  * we call here to look for a TGA device, and proceed...
  */
-void
-tga_console_init(void)
+__initfunc(void
+tga_console_init(void))
 {
 	unsigned char pci_bus, pci_devfn;
 	int status;
@@ -490,9 +491,9 @@
 #endif
 }
 
-unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
+unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
 
-const unsigned long bt485_cursor_source[64] = {
+const unsigned long bt485_cursor_source[64] __initdata = {
   0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
   0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
   0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
@@ -502,7 +503,7 @@
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 };
 
-const unsigned int bt463_cursor_source[256] = {
+const unsigned int bt463_cursor_source[256] __initdata = {
   0xffff0000, 0x00000000, 0x00000000, 0x00000000,
   0xffff0000, 0x00000000, 0x00000000, 0x00000000,
   0xffff0000, 0x00000000, 0x00000000, 0x00000000,
@@ -533,8 +534,8 @@
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 };
 
-void
-tga_init_video()
+__initfunc(void
+tga_init_video(void))
 {
 	int i, j, temp;
 	unsigned char *cbp;
@@ -750,8 +751,8 @@
 	tga_fb_stride = tga_fb_width / sizeof(int);
 }
 
-void
-tga_clear_screen()
+__initfunc(void
+tga_clear_screen(void))
 {
     register int i, j;
     register unsigned int *dst;
diff -u --recursive --new-file v2.1.36/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.1.36/linux/drivers/char/tpqic02.c	Fri Apr  4 08:52:19 1997
+++ linux/drivers/char/tpqic02.c	Mon May 12 10:35:40 1997
@@ -89,6 +89,7 @@
 #include <linux/tpqic02.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
  
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -2866,10 +2867,7 @@
     return 0;
 } /* qic02_get_resources */
 
-#ifdef MODULE
-static
-#endif
-int qic02_tape_init(void)
+__initfunc(static int qic02_tape_init(void))
 {
     if (TPSTATSIZE != 6)
     {
diff -u --recursive --new-file v2.1.36/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.36/linux/drivers/char/tty_io.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/tty_io.c	Mon May 12 10:35:40 1997
@@ -166,14 +166,11 @@
 {
 #ifdef CHECK_TTY_COUNT
 	struct file *f;
-	int i, count = 0;
+	int count = 0;
 	
-	for (f = first_file, i=0; i<nr_files; i++, f = f->f_next) {
-		if (!f->f_count)
-			continue;
-		if (f->private_data == tty) {
+	for(f = inuse_filps; f; f = f->f_next) {
+		if(f->private_data == tty)
 			count++;
-		}
 	}
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver.subtype == PTY_TYPE_SLAVE &&
@@ -363,16 +360,14 @@
 
 void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
 {
-	int i;
+
 	struct file * filp;
 	struct task_struct *p;
 
 	if (!tty)
 		return;
 	check_tty_count(tty, "do_tty_hangup");
-	for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
-		if (!filp->f_count)
-			continue;
+	for (filp = inuse_filps; filp; filp = filp->f_next) {
 		if (filp->private_data != tty)
 			continue;
 		if (!filp->f_inode)
@@ -405,13 +400,14 @@
 		tty->ldisc = ldiscs[N_TTY];
 		tty->termios->c_line = N_TTY;
 		if (tty->ldisc.open) {
-			i = (tty->ldisc.open)(tty);
+			int i = (tty->ldisc.open)(tty);
 			if (i < 0)
 				printk("do_tty_hangup: N_TTY open: error %d\n",
 				       -i);
 		}
 	}
 	
+	read_lock(&tasklist_lock);
  	for_each_task(p) {
 		if ((tty->session > 0) && (p->session == tty->session) &&
 		    p->leader) {
@@ -423,6 +419,8 @@
 		if (p->tty == tty)
 			p->tty = NULL;
 	}
+	read_unlock(&tasklist_lock);
+
 	tty->flags = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
@@ -494,9 +492,11 @@
 	tty->session = 0;
 	tty->pgrp = -1;
 
+	read_lock(&tasklist_lock);
 	for_each_task(p)
 	  	if (p->session == current->session)
 			p->tty = NULL;
+	read_unlock(&tasklist_lock);
 }
 
 void wait_for_keypress(void)
@@ -1338,9 +1338,11 @@
 			 */
 			struct task_struct *p;
 
+			read_lock(&tasklist_lock);
 			for_each_task(p)
 				if (p->tty == tty)
 					p->tty = NULL;
+			read_unlock(&tasklist_lock);
 		} else
 			return -EPERM;
 	}
@@ -1760,6 +1762,9 @@
 #endif
 #ifdef CONFIG_DIGI
 	pcxe_init();
+#endif
+#ifdef CONFIG_DIGIEPCA
+	pc_init();
 #endif
 #ifdef CONFIG_RISCOM8
 	riscom8_init();
diff -u --recursive --new-file v2.1.36/linux/drivers/char/vga.c linux/drivers/char/vga.c
--- v2.1.36/linux/drivers/char/vga.c	Mon Apr  7 11:35:29 1997
+++ linux/drivers/char/vga.c	Mon May 12 10:35:40 1997
@@ -53,6 +53,7 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -146,8 +147,8 @@
 		hide_cursor();
 }
 
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
 {
 	if (ORIG_VIDEO_MODE == 7)	/* Is this a monochrome display? */
 	{
@@ -239,8 +240,8 @@
 	return kmem_start;
 }
 
-void
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
 {
 }
 
diff -u --recursive --new-file v2.1.36/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.36/linux/drivers/char/vt.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/vt.c	Mon May 12 10:35:40 1997
@@ -123,6 +123,7 @@
 	}
     }
 
+  read_lock(&tasklist_lock);
   for_each_task(p)
     {
       if ( p->tty && MAJOR(p->tty->device) == TTY_MAJOR &&
@@ -131,6 +132,7 @@
 	  send_sig(SIGWINCH, p, 1);
 	}
     }
+  read_unlock(&tasklist_lock);
 
   return 0;
 }
diff -u --recursive --new-file v2.1.36/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v2.1.36/linux/drivers/char/wdt.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/wdt.c	Mon May 12 10:35:40 1997
@@ -61,7 +61,7 @@
  *	Setup options
  */
  
-void wdt_setup(char *str, int *ints)
+__initfunc(void wdt_setup(char *str, int *ints))
 {
 	if(ints[0]>0)
 	{
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- v2.1.36/linux/drivers/isdn/Config.in	Thu Feb 27 10:57:29 1997
+++ linux/drivers/isdn/Config.in	Mon May 12 10:35:40 1997
@@ -11,7 +11,6 @@
 bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
 dep_tristate 'ICN 2B and 4B 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
 dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
     bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile
--- v2.1.36/linux/drivers/isdn/Makefile	Thu Feb 27 10:57:29 1997
+++ linux/drivers/isdn/Makefile	Mon May 12 10:35:40 1997
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit hisax
+ALL_SUB_DIRS := icn pcbit hisax
 
 L_OBJS :=
 LX_OBJS :=
@@ -33,16 +33,6 @@
     ifdef CONFIG_ISDN_AUDIO
       O_OBJS += isdn_audio.o
     endif
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
-  L_OBJS += teles/teles.o
-  SUB_DIRS += teles
-  MOD_SUB_DIRS += teles
-else
-  ifeq ($(CONFIG_ISDN_DRV_TELES),m)
-    MOD_SUB_DIRS += teles
   endif
 endif
 
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.1.36/linux/drivers/isdn/hisax/isdnl1.c	Thu Feb 27 10:57:29 1997
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon May 12 17:39:50 1997
@@ -461,11 +461,11 @@
 	if (!sp)
 		return;
 
-	if (clear_bit(ISAC_PHCHANGE, &sp->event))
+	if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
 		process_new_ph(sp);
-	if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
+	if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
 		process_rcv(sp);
-	if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
+	if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
 		process_xmt(sp);
 }
 
@@ -578,9 +578,9 @@
 	if (!hsp)
 		return;
 
-	if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+	if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
 		hscx_process_rcv(hsp);
-	if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+	if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
 		hscx_process_xmt(hsp);
 
 }
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.1.36/linux/drivers/isdn/isdn_net.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/isdn_net.c	Mon May 12 17:39:50 1997
@@ -934,7 +934,7 @@
 		return 0;
 	}
 	/* Avoid timer-based retransmission conflicts. */
-	if (set_bit(0, (void *) &ndev->tbusy) != 0)
+	if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
 		printk(KERN_WARNING
 		       "%s: Transmitter access conflict.\n",
 		       ndev->name);
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/sc/Makefile linux/drivers/isdn/sc/Makefile
--- v2.1.36/linux/drivers/isdn/sc/Makefile	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/sc/Makefile	Mon May 12 10:35:40 1997
@@ -1,5 +1,5 @@
 #
-#  $Id: Makefile.kernel,v 1.1 1996/11/07 13:07:40 fritz Exp $
+#  $Id: Makefile,v 1.2 1997/05/01 08:53:47 davem Exp $
 #  Copyright (C) 1996  SpellCaster Telecommunications Inc.
 #
 #  This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/Makefile linux/drivers/isdn/teles/Makefile
--- v2.1.36/linux/drivers/isdn/teles/Makefile	Mon Feb 26 01:58:05 1996
+++ linux/drivers/isdn/teles/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
-llglue.o q931.o callc.o fsm.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
-  O_TARGET += teles.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_TELES),m)
-    O_TARGET += teles.o
-    M_OBJS += teles.o
-  endif
-endif
-
-include $(TOPDIR)/Rules.make
- 
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/buffers.c linux/drivers/isdn/teles/buffers.c
--- v2.1.36/linux/drivers/isdn/teles/buffers.c	Sat Jun  1 01:56:51 1996
+++ linux/drivers/isdn/teles/buffers.c	Wed Dec 31 16:00:00 1969
@@ -1,326 +0,0 @@
-/* $Id: buffers.c,v 1.3 1996/05/31 00:56:53 fritz Exp $
- *
- * $Log: buffers.c,v $
- * Revision 1.3  1996/05/31 00:56:53  fritz
- * removed cli() from BufPoolAdd, since it is called
- * with interrupts off anyway.
- *
- * Revision 1.2  1996/04/29 22:48:14  fritz
- * Removed compatibility-macros. No longer needed.
- *
- * Revision 1.1  1996/04/13 10:19:28  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
-	    int maxpages)
-{
-#ifdef DEBUG_MAGIC
-	generateerror
-	    bp->magic = 010167;
-#endif
-
-#if 0
-	printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
-	bp->freelist = NULL;
-	bp->pageslist = NULL;
-	bp->pageorder = order;
-	bp->pagescount = 0;
-	bp->bpps = bpps;
-	bp->bufsize = BUFFER_SIZE(order, bpps);
-	bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
-	struct Pages   *ptr;
-	byte           *bptr;
-	int             i;
-	struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
-	printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
-	ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
-	if (!ptr) {
-		printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
-		return (-1);
-	}
-#if 0
-	printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
-	ptr->next = bp->pageslist;
-	bp->pageslist = ptr;
-	bp->pagescount++;
-
-	bptr = (byte *) ptr + sizeof(struct Pages *);
-
-	i = bp->bpps;
-	first = (struct BufHeader *) bptr;
-	prev = NULL;
-	while (i--) {
-		bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
-		bh->magic = 020167;
-#endif
-		bh->next = prev;
-		prev = bh;
-		bh->bp = bp;
-		bptr += PART_SIZE(bp->pageorder, bp->bpps);
-	}
-
-	first->next = bp->freelist;
-	bp->freelist = bh;
-	return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
-	struct Pages   *p;
-
-#if 0
-	printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
-	while (bp->pagescount--) {
-		p = bp->pageslist->next;
-		free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
-		printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
-		bp->pageslist = p;
-	}
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
-	   struct BufPool *bp, int priority, void *heldby, int where)
-{
-	long            flags;
-	int             i;
-
-#ifdef DEBUG_MAGIC
-	if (bp->magic != 010167) {
-		printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
-		return (-1);
-	}
-#endif
-
-	save_flags(flags);
-	cli();
-	i = 0;
-	while (!0) {
-		if (bp->freelist) {
-			*bh = bp->freelist;
-			bp->freelist = bp->freelist->next;
-			(*bh)->heldby = heldby;
-			(*bh)->where = where;
-			restore_flags(flags);
-			return (0);
-		}
-		if ((i == 0) && (bp->pagescount < bp->maxpages)) {
-                        if (BufPoolAdd(bp, priority)) {
-                                restore_flags(flags);
-                                return -1;
-                        }
-			i++;
-		} else {
-			*bh = NULL;
-			restore_flags(flags);
-			return (-1);
-		}
-	}
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
-	struct BufPool *bp;
-	long            flags;
-
-#ifdef DEBUG_MAGIC
-	if (bh->magic != 020167) {
-		printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
-		printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
-		return;
-	}
-#endif
-
-	bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
-	if (bp->magic != 010167) {
-		printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
-		return;
-	}
-#endif
-
-	save_flags(flags);
-	cli();
-	bh->next = bp->freelist;
-	bp->freelist = bh;
-	restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
-	     struct BufHeader *bh)
-{
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-	if (!bq->head)
-		bq->head = bh;
-	if (bq->tail)
-		bq->tail->next = bh;
-	bq->tail = bh;
-	bh->next = NULL;
-	restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
-		  struct BufHeader *bh)
-{
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-	bh->next = bq->head;
-	bq->head = bh;
-	if (!bq->tail)
-		bq->tail = bh;
-	restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-
-	if (bq->head) {
-		if (bq->tail == bq->head)
-			bq->tail = NULL;
-		*bh = bq->head;
-		bq->head = (*bh)->next;
-		restore_flags(flags);
-		return (0);
-	} else {
-		restore_flags(flags);
-		return (-1);
-	}
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
-	bq->magic = 030167;
-#endif
-	bq->head = NULL;
-	bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
-	struct BufHeader *bh;
-
-	while (bq->head) {
-		BufQueueUnlink(&bh, bq);
-		BufPoolRelease(bh);
-	}
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
-	int             i = 0;
-	struct BufHeader *bh;
-
-	bh = bq->head;
-	while (bh) {
-		i++;
-		bh = bh->next;
-	}
-	return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
-		int releasetoo)
-{
-	long            flags;
-	struct BufHeader *sp;
-
-	save_flags(flags);
-	cli();
-
-	while (!0) {
-		sp = q->head;
-		if (!sp)
-			break;
-		if ((sp->primitive == pr) && (sp->heldby == heldby)) {
-			q->head = sp->next;
-			if (q->tail == sp)
-				q->tail = NULL;
-			if (releasetoo)
-				BufPoolRelease(sp);
-		} else
-			break;
-	}
-
-	sp = q->head;
-	if (sp)
-		while (sp->next) {
-			if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
-				if (q->tail == sp->next)
-					q->tail = sp;
-				if (releasetoo)
-					BufPoolRelease(sp->next);
-				sp->next = sp->next->next;
-			} else
-				sp = sp->next;
-		}
-	restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#if 0
-	printk(KERN_DEBUG "Sfree %x\n", ptr);
-#endif
-	kfree(ptr);
-}
-
-byte           *
-Smalloc(int size, int pr, char *why)
-{
-	byte           *p;
-
-	p = (byte *) kmalloc(size, pr);
-#if 0
-	printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p);
-#endif
-	return (p);
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c
--- v2.1.36/linux/drivers/isdn/teles/callc.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/callc.c	Wed Dec 31 16:00:00 1969
@@ -1,1453 +0,0 @@
-/* $Id: callc.c,v 1.16 1997/02/11 01:39:46 keil Exp $
- *
- * $Log: callc.c,v $
- * Revision 1.16  1997/02/11 01:39:46  keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.15  1996/11/23 11:32:20  keil
- * windowsize = 7 X.75 bugfix Thanks to Martin Maurer
- *
- * Revision 1.14  1996/10/22 23:14:14  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.13  1996/06/24 17:15:55  fritz
- * corrected return code of teles_writebuf()
- *
- * Revision 1.12  1996/06/12 16:15:33  fritz
- * Extended user-configurable debugging flags.
- *
- * Revision 1.11  1996/06/07 12:32:20  fritz
- * More changes to support suspend/resume.
- *
- * Revision 1.10  1996/06/06 21:24:21  fritz
- * Started adding support for suspend/resume.
- *
- * Revision 1.9  1996/05/31 12:23:57  jdenoud
- * Jan: added channel open check to teles_writebuf
- *
- * Revision 1.8  1996/05/31 01:00:38  fritz
- * Changed return code of teles_writebuf, when out of memory.
- *
- * Revision 1.7  1996/05/17 03:40:37  fritz
- * General cleanup.
- *
- * Revision 1.6  1996/05/10 22:42:07  fritz
- * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
- *
- * Revision 1.5  1996/05/06 10:16:15  fritz
- * Added voice stuff.
- *
- * Revision 1.4  1996/04/30 22:04:05  isdn4dev
- *   improved callback  Karsten Keil
- *
- * Revision 1.3  1996/04/30 10:04:19  fritz
- * Started voice support.
- * Added printk() to debug-switcher for easier
- * synchronization between printk()'s and output
- * of /dev/isdnctrl.
- *
- * Revision 1.2  1996/04/20 16:42:29  fritz
- * Changed statemachine to allow reject of incoming calls.
- *
- * Revision 1.1  1996/04/13 10:20:59  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int      nrcards;
-extern int      drid;
-extern isdn_if  iif;
-extern void     teles_mod_dec_use_count(void);
-extern void     teles_mod_inc_use_count(void);
-
-static int      init_ds(int chan, int incoming);
-static void     release_ds(int chan);
-
-static struct Fsm callcfsm =
-{NULL, 0, 0},   lcfsm =
-{NULL, 0, 0};
-
-struct Channel *chanlist;
-static int      chancount = 0;
-unsigned int    debugflags = 0;
-
-#define TMR_DCHAN_EST 2000
-
-static void
-stat_debug(struct Channel *chanp, char *s)
-{
-	char            tmp[100], tm[32];
-
-	jiftime(tm, jiffies);
-	sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
-	teles_putstatus(tmp);
-}
-
-enum {
-        ST_NULL,           /*  0 inactive                                               */
-        ST_OUT,            /*  1 outgoing, awaiting SETUP confirm                       */
-        ST_CLEAR,          /*  2 call release, awaiting RELEASE confirm                 */
-        ST_OUT_W,          /*  3 outgoing, awaiting d-channel establishment             */
-        ST_REL_W,          /*  4 awaiting d-channel release                             */
-        ST_IN_W,           /*  5 incoming, awaiting d-channel establishment             */
-        ST_IN,             /*  6 incoming call received                                 */
-        ST_IN_SETUP,       /*  7 incoming, SETUP response sent                          */
-        ST_IN_DACT,        /*  8 incoming connected, no b-channel prot.                 */
-        ST_OUT_ESTB,       /* 10 outgoing connected, awaiting b-channel prot. estbl.    */
-        ST_ACTIVE,         /* 11 active, b channel prot. established                    */
-        ST_BC_HANGUP,      /* 12 call clear. (initiator), awaiting b channel prot. rel. */
-        ST_PRO_W,          /* 13 call clear. (initiator), DISCONNECT req. sent          */
-        ST_ANT_W,          /* 14 call clear. (receiver), awaiting DISCONNECT ind.       */
-        ST_DISC_BC_HANGUP, /*    d channel gone, wait for b channel deactivation        */
-	ST_OUT_W_HANGUP,      /* Outgoing waiting for D-Channel hangup received */ 
-        ST_D_ERR,          /*    d channel released while active                        */
-};
-
-#define STATE_COUNT (ST_D_ERR+1)
-
-static char    *strState[] =
-{
-        "ST_NULL",
-        "ST_OUT",
-        "ST_CLEAR",
-        "ST_OUT_W",
-        "ST_REL_W",
-        "ST_IN_W",
-        "ST_IN",
-        "ST_IN_SETUP",
-        "ST_IN_DACT",
-        "ST_OUT_ESTB",
-        "ST_ACTIVE",
-        "ST_BC_HANGUP",
-        "ST_PRO_W",
-        "ST_ANT_W",
-        "ST_DISC_BC_HANGUP",
-        "ST_OUT_W_HANGUP",
-        "ST_D_ERR",
-};
-
-enum {
-        EV_DIAL,           /*  0 */
-        EV_SETUP_CNF,      /*  1 */
-        EV_ACCEPTB,        /*  2 */
-        EV_DISCONNECT_CNF, /*  5 */
-        EV_DISCONNECT_IND, /*  6 */
-        EV_RELEASE_CNF,    /*  7 */
-        EV_DLEST,          /*  8 */
-        EV_DLRL,           /*  9 */
-        EV_SETUP_IND,      /* 10 */
-        EV_RELEASE_IND,    /* 11 */
-        EV_ACCEPTD,        /* 12 */
-        EV_SETUP_CMPL_IND, /* 13 */
-        EV_BC_EST,         /* 14 */
-        EV_WRITEBUF,       /* 15 */
-        EV_DATAIN,         /* 16 */
-        EV_HANGUP,         /* 17 */
-        EV_BC_REL,         /* 18 */
-        EV_CINF,           /* 19 */
-        EV_SUSPEND,        /* 20 */
-        EV_RESUME,         /* 21 */
-};
-
-#define EVENT_COUNT (EV_CINF+1)
-
-static char    *strEvent[] =
-{
-        "EV_DIAL",
-        "EV_SETUP_CNF",
-        "EV_ACCEPTB",
-        "EV_DISCONNECT_CNF",
-        "EV_DISCONNECT_IND",
-        "EV_RELEASE_CNF",
-        "EV_DLEST",
-        "EV_DLRL",
-        "EV_SETUP_IND",
-        "EV_RELEASE_IND",
-        "EV_ACCEPTD",
-        "EV_SETUP_CMPL_IND",
-        "EV_BC_EST",
-        "EV_WRITEBUF",
-        "EV_DATAIN",
-        "EV_HANGUP",
-        "EV_BC_REL",
-        "EV_CINF",
-        "EV_SUSPEND",
-        "EV_RESUME",
-};
-
-enum {
-        ST_LC_NULL,
-        ST_LC_ACTIVATE_WAIT,
-        ST_LC_DELAY,
-        ST_LC_ESTABLISH_WAIT,
-        ST_LC_CONNECTED,
-        ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char    *strLcState[] =
-{
-        "ST_LC_NULL",
-        "ST_LC_ACTIVATE_WAIT",
-        "ST_LC_DELAY",
-        "ST_LC_ESTABLISH_WAIT",
-        "ST_LC_CONNECTED",
-        "ST_LC_RELEASE_WAIT",
-};
-
-enum {
-        EV_LC_ESTABLISH,
-        EV_LC_PH_ACTIVATE,
-        EV_LC_PH_DEACTIVATE,
-        EV_LC_DL_ESTABLISH,
-        EV_LC_TIMER,
-        EV_LC_DL_RELEASE,
-        EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char    *strLcEvent[] =
-{
-        "EV_LC_ESTABLISH",
-        "EV_LC_PH_ACTIVATE",
-        "EV_LC_PH_DEACTIVATE",
-        "EV_LC_DL_ESTABLISH",
-        "EV_LC_TIMER",
-        "EV_LC_DL_RELEASE",
-        "EV_LC_RELEASE",
-};
-
-#define LC_D  0
-#define LC_B  1
-
-/*
- * Dial out
- */
-static void
-r1(struct FsmInst *fi, int event, void *arg)
-{
-        isdn_ctrl      *ic = arg;
-        struct Channel *chanp = fi->userdata;
-
-	chanp->para.setup = ic->parm.setup;
-	if (!strcmp(chanp->para.setup.eazmsn, "0"))
-		chanp->para.setup.eazmsn[0] = '\0';
-
-        chanp->l2_active_protocol = chanp->l2_protocol;
-        chanp->incoming = 0;
-        chanp->lc_b.l2_start = !0;
-
-        switch (chanp->l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  chanp->lc_b.l2_establish = !0;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  chanp->lc_b.l2_establish = 0;
-                  break;
-          default:
-                  printk(KERN_WARNING "r1 unknown protocol\n");
-                  break;
-        }
-
-        FsmChangeState(fi, ST_OUT_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-ll_hangup(struct Channel *chanp, int bchantoo)
-{
-        isdn_ctrl       ic;
-
-        if (bchantoo) {
-                if (chanp->debug & 1)
-                        stat_debug(chanp, "STAT_BHUP");
-                ic.driver = drid;
-                ic.command = ISDN_STAT_BHUP;
-                ic.arg = chanp->chan;
-                iif.statcallb(&ic);
-        }
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_DHUP");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_DHUP;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static void
-r2(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        FsmChangeState(fi, ST_CLEAR);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r2_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-
-        FsmChangeState(fi, ST_OUT_W_HANGUP);
-}
-
-
-static void
-r2_2(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_REL_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r3(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        FsmChangeState(fi, ST_REL_W);
-}
-
-
-static void
-r3_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-	
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        FsmChangeState(fi, ST_REL_W);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r4(struct FsmInst *fi, int event, void *arg)
-{
-	struct Channel *chanp=fi->userdata;  
-  
-        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);                                  
-        FsmChangeState(fi, ST_NULL);
-}
-
-static void
-r5(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->para.callref = chanp->outcallref;
-
-        chanp->outcallref++;
-        if (chanp->outcallref == 128)
-                chanp->outcallref = 64;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
-
-        FsmChangeState(fi, ST_OUT);
-}
-
-static void
-r6(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r7(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-        /*
-         * Report incoming calls only once to linklevel, use octet 3 of
-         * channel identification information element. (it's value
-         * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c)
-         */
-        if (((chanp->chan & 1) + 1) & chanp->para.bchannel) {
-                chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
-                FsmChangeState(fi, ST_IN);
-                if (chanp->debug & 1)
-                        stat_debug(chanp, "STAT_ICALL");
-                ic.driver = drid;
-                ic.command = ISDN_STAT_ICALL;
-                ic.arg = chanp->chan;
-                /*
-                 * No need to return "unknown" for calls without OAD,
-                 * cause that's handled in linklevel now (replaced by '0')
-                 */
-		ic.parm.setup = chanp->para.setup;
-                iif.statcallb(&ic);
-        } else {
-                chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-                FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-                FsmChangeState(fi, ST_REL_W);
-        }
-}
-
-static void
-r8(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_SETUP);
-        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
-
-}
-
-static void
-r9(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_DACT);
-
-        chanp->l2_active_protocol = chanp->l2_protocol;
-        chanp->incoming = !0;
-        chanp->lc_b.l2_start = 0;
-
-        switch (chanp->l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  chanp->lc_b.l2_establish = !0;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  chanp->lc_b.l2_establish = 0;
-                  break;
-          default:
-                  printk(KERN_WARNING "r9 unknown protocol\n");
-                  break;
-        }
-
-        init_ds(chanp->chan, !0);
-
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r10(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_OUT_ESTB);
-
-        init_ds(chanp->chan, 0);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-
-}
-
-static void
-r12(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-        FsmChangeState(fi, ST_ACTIVE);
-        chanp->data_open = !0;
-
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_DCONN");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_DCONN;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_BCONN");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_BCONN;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static void
-r15(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_BC_HANGUP);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r16(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_PRO_W);
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r17(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_ANT_W);
-}
-
-
-static void
-r17_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        release_ds(chanp->chan);
-
-	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-	
-	FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
-	
-        FsmChangeState(fi, ST_NULL);
-        
-        ll_hangup(chanp,!0); 
-}
-
-static void
-r18(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_REL_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r19(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_CLEAR);
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r20(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        
-        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-        
-        FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
-
-        FsmChangeState(fi, ST_NULL);
-
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r21(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_DISC_BC_HANGUP);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r22(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_CLEAR);
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r23(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_PRO_W);
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r23_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-	chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL); 
-	
-	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL); 
-	
-        FsmChangeState(fi, ST_NULL);
-        
-        ll_hangup(chanp,!0); 
-}
-
-static void
-r24(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_D_ERR);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r25(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r26(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-
-        ic.driver = drid;
-        ic.command = ISDN_STAT_CINF;
-        ic.arg = chanp->chan;
-        sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
-        iif.statcallb(&ic);
-}
-
-
-
-static struct FsmNode fnlist[] =
-{
-        {ST_NULL,             EV_DIAL,                r1},
-        {ST_OUT_W,            EV_DLEST,               r5},
-        {ST_OUT_W,            EV_DLRL,                r20},
-        {ST_OUT_W,            EV_RELEASE_CNF,         r2_2 },   
-        {ST_OUT,              EV_DISCONNECT_IND,      r2},
-        {ST_OUT,              EV_SETUP_CNF,           r10},
-        {ST_OUT,              EV_HANGUP,              r2_1},
-        {ST_OUT,              EV_RELEASE_IND,         r20},
-        {ST_OUT,              EV_RELEASE_CNF,         r20},
-        {ST_OUT,              EV_DLRL,                r2_2},
-        {ST_OUT_W_HANGUP,     EV_RELEASE_IND,         r2_2},
-        {ST_OUT_W_HANGUP,     EV_DLRL,                r20},
-        {ST_CLEAR,            EV_RELEASE_CNF,         r3},
-        {ST_CLEAR,            EV_DLRL,                r20},
-        {ST_REL_W,            EV_DLRL,                r4},
-        {ST_NULL,             EV_SETUP_IND,           r6},
-        {ST_IN_W,             EV_DLEST,               r7},
-        {ST_IN_W,             EV_DLRL,                r3_1},
-        {ST_IN,               EV_DLRL,                r3_1},
-        {ST_IN,               EV_HANGUP,              r2_1},
-        {ST_IN,               EV_RELEASE_IND,         r2_2},
-        {ST_IN,               EV_RELEASE_CNF,         r2_2},
-        {ST_IN,               EV_ACCEPTD,             r8},
-        {ST_IN_SETUP,         EV_HANGUP,              r2_1},
-        {ST_IN_SETUP,         EV_SETUP_CMPL_IND,      r9},
-        {ST_IN_SETUP,         EV_RELEASE_IND,         r2_2},
-        {ST_IN_SETUP,         EV_DISCONNECT_IND,      r2},
-        {ST_IN_SETUP,         EV_DLRL,                r20},
-        {ST_OUT_ESTB,         EV_BC_EST,              r12},
-        {ST_OUT_ESTB,         EV_BC_REL,              r23},
-        {ST_OUT_ESTB,         EV_DLRL,                r23_1},
-        {ST_IN_DACT,          EV_BC_EST,              r12},
-        {ST_IN_DACT,          EV_BC_REL,              r17},
-        {ST_IN_DACT,          EV_DLRL,                r17_1},
-        {ST_ACTIVE,           EV_HANGUP,              r15},
-        {ST_ACTIVE,           EV_BC_REL,              r17},
-        {ST_ACTIVE,           EV_DISCONNECT_IND,      r21},
-        {ST_ACTIVE,           EV_DLRL,                r24},
-        {ST_ACTIVE,           EV_CINF,                r26},
-        {ST_ACTIVE,           EV_RELEASE_IND,         r17},
-        {ST_BC_HANGUP,        EV_BC_REL,              r16},
-        {ST_BC_HANGUP,        EV_DISCONNECT_IND,      r21},
-        {ST_PRO_W,            EV_RELEASE_IND,         r18},
-        {ST_ANT_W,            EV_DISCONNECT_IND,      r19},
-        {ST_DISC_BC_HANGUP,   EV_BC_REL,              r22},
-        {ST_D_ERR,            EV_BC_REL,              r25},
-};
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
-        FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
-        lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmDelTimer(&lf->act_timer, 50);
-        FsmChangeState(fi, ST_LC_DELAY);
-        FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        if (lf->l2_establish) {
-                FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
-                if (lf->l2_start)
-                        lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
-        } else {
-                FsmChangeState(fi, ST_LC_CONNECTED);
-                lf->lccall(lf, LC_ESTABLISH, NULL);
-        }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_CONNECTED);
-        lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        if (lf->l2_establish) {
-                FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-                lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
-        } else {
-                FsmChangeState(fi, ST_LC_NULL);
-                lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-                lf->lccall(lf, LC_RELEASE, NULL);
-        }
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_NULL);
-        lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-        lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static struct FsmNode LcFnList[] =
-{
-        {ST_LC_NULL,                  EV_LC_ESTABLISH,        lc_r1},
-        {ST_LC_ACTIVATE_WAIT,         EV_LC_PH_ACTIVATE,      lc_r6},
-        {ST_LC_DELAY,                 EV_LC_TIMER,            lc_r2},
-        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_ESTABLISH,     lc_r3},
-        {ST_LC_CONNECTED,             EV_LC_RELEASE,          lc_r4},
-        {ST_LC_CONNECTED,             EV_LC_DL_RELEASE,       lc_r5},
-        {ST_LC_RELEASE_WAIT,          EV_LC_DL_RELEASE,       lc_r5},
-        {ST_LC_ACTIVATE_WAIT,         EV_LC_TIMER,            lc_r5},
-        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_RELEASE,       lc_r5},
-};
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
-void
-CallcNew(void)
-{
-        callcfsm.state_count = STATE_COUNT;
-        callcfsm.event_count = EVENT_COUNT;
-        callcfsm.strEvent = strEvent;
-        callcfsm.strState = strState;
-        FsmNew(&callcfsm, fnlist, FNCOUNT);
-
-        lcfsm.state_count = LC_STATE_COUNT;
-        lcfsm.event_count = LC_EVENT_COUNT;
-        lcfsm.strEvent = strLcEvent;
-        lcfsm.strState = strLcState;
-        FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
-}
-
-void
-CallcFree(void)
-{
-        FsmFree(&lcfsm);
-        FsmFree(&callcfsm);
-}
-
-static void
-release_ds(int chan)
-{
-        struct PStack  *st = &chanlist[chan].ds;
-        struct IsdnCardState *sp;
-        struct HscxState *hsp;
-
-        sp = st->l1.hardware;
-        hsp = sp->hs + chanlist[chan].hscx;
-
-        close_hscxstate(hsp);
-
-        switch (chanlist[chan].l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  releasestack_isdnl2(st);
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  releasestack_transl2(st);
-                  break;
-        }
-}
-
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (PH_ACTIVATE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                  break;
-          case (PH_DEACTIVATE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                  break;
-        }
-}
-
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (DL_ESTABLISH):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
-                  break;
-          case (DL_RELEASE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
-                  break;
-        }
-}
-
-static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (PH_ACTIVATE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                  break;
-          case (PH_DEACTIVATE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                  break;
-        }
-}
-
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (DL_ESTABLISH):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
-                  break;
-          case (DL_RELEASE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
-                  break;
-        }
-}
-
-static void
-ll_handler(struct PStack *st, int pr,
-           struct BufHeader *ibh)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (CC_DISCONNECT_IND):
-                  FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
-                  break;
-          case (CC_RELEASE_CNF):
-                  FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
-                  break;
-          case (CC_SETUP_IND):
-                  FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
-                  break;
-          case (CC_RELEASE_IND):
-                  FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
-                  break;
-          case (CC_SETUP_COMPLETE_IND):
-                  FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
-                  break;
-          case (CC_SETUP_CNF):
-                  FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
-                  break;
-          case (CC_INFO_CHARGE):
-                  FsmEvent(&chanp->fi, EV_CINF, NULL);
-                  break;
-        }
-}
-
-static void
-init_is(int chan, unsigned int ces)
-{
-        struct PStack  *st = &(chanlist[chan].is);
-        struct IsdnCardState *sp = chanlist[chan].sp;
-        char            tmp[128];
-
-        setstack_teles(st, sp);
-
-        st->l2.sap = 0;
-
-        st->l2.tei = 255;
-
-        st->l2.ces = ces;
-        st->l2.extended = !0;
-        st->l2.laptype = LAPD;
-        st->l2.window = 1;
-        st->l2.orig = !0;
-        st->l2.t200 = 1000;               /* 1000 milliseconds  */
-        if (st->protocol == ISDN_PTYPE_1TR6) {
-                st->l2.n200 = 3;          /* try 3 times        */
-                st->l2.t203 = 10000;      /* 10000 milliseconds */
-        } else {
-                st->l2.n200 = 4;          /* try 4 times        */
-                st->l2.t203 = 5000;       /* 5000 milliseconds  */
-        }
-
-        sprintf(tmp, "Channel %d q.921", chan);
-        setstack_isdnl2(st, tmp);
-        setstack_isdnl3(st);
-        st->l2.debug = 2;
-        st->l3.debug = 2;
-        st->l2.debug = 0xff;
-        st->l3.debug = 0xff;
-        st->l4.userdata = chanlist + chan;
-        st->l4.l2writewakeup = NULL;
-
-        st->l3.l3l4 = ll_handler;
-        st->l1.l1man = cc_l1man;
-        st->l2.l2man = cc_l2man;
-
-        st->pa = &chanlist[chan].para;
-        teles_addlist(sp, st);
-}
-
-static void
-callc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[80], tm[32];
-        struct Channel *chanp = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[256], tm[32];
-        struct LcFsm   *lf = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[256], tm[32];
-        struct LcFsm   *lf = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
-        struct Channel *chanp = lf->ch;
-
-        switch (pr) {
-          case (LC_ESTABLISH):
-                  FsmEvent(&chanp->fi, EV_DLEST, NULL);
-                  break;
-          case (LC_RELEASE):
-                  FsmEvent(&chanp->fi, EV_DLRL, NULL);
-                  break;
-        }
-}
-
-static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
-        struct Channel *chanp = lf->ch;
-
-        switch (pr) {
-          case (LC_ESTABLISH):
-                  FsmEvent(&chanp->fi, EV_BC_EST, NULL);
-                  break;
-          case (LC_RELEASE):
-                  FsmEvent(&chanp->fi, EV_BC_REL, NULL);
-                  break;
-        }
-}
-
-static void
-init_chan(int chan, int cardnr, int hscx,
-          unsigned int ces)
-{
-        struct IsdnCard *card = cards + cardnr;
-        struct Channel *chanp = chanlist + chan;
-
-        chanp->sp = card->sp;
-        chanp->hscx = hscx;
-        chanp->chan = chan;
-        chanp->incoming = 0;
-        chanp->debug = 0;
-        init_is(chan, ces);
-
-        chanp->fi.fsm = &callcfsm;
-        chanp->fi.state = ST_NULL;
-        chanp->fi.debug = 0;
-        chanp->fi.userdata = chanp;
-        chanp->fi.printdebug = callc_debug;
-
-        chanp->lc_d.lcfi.fsm = &lcfsm;
-        chanp->lc_d.lcfi.state = ST_LC_NULL;
-        chanp->lc_d.lcfi.debug = 0;
-        chanp->lc_d.lcfi.userdata = &chanp->lc_d;
-        chanp->lc_d.lcfi.printdebug = lc_debug;
-        chanp->lc_d.type = LC_D;
-        chanp->lc_d.ch = chanp;
-        chanp->lc_d.st = &chanp->is;
-        chanp->lc_d.l2_establish = !0;
-        chanp->lc_d.l2_start = !0;
-        chanp->lc_d.lccall = lccall_d;
-        FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
-        chanp->lc_b.lcfi.fsm = &lcfsm;
-        chanp->lc_b.lcfi.state = ST_LC_NULL;
-        chanp->lc_b.lcfi.debug = 0;
-        chanp->lc_b.lcfi.userdata = &chanp->lc_b;
-        chanp->lc_b.lcfi.printdebug = dlc_debug;
-        chanp->lc_b.type = LC_B;
-        chanp->lc_b.ch = chanp;
-        chanp->lc_b.st = &chanp->ds;
-        chanp->lc_b.l2_establish = !0;
-        chanp->lc_b.l2_start = !0;
-        chanp->lc_b.lccall = lccall_b;
-        FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
-
-        chanp->outcallref = 64;
-        chanp->data_open = 0;
-}
-
-int
-CallcNewChan(void)
-{
-        int             i, ces, c;
-
-        chancount = 0;
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp)
-                        chancount += 2;
-
-        chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
-                                      chancount, GFP_KERNEL, "chanlist");
-
-        c = 0;
-        ces = randomces();
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp) {
-                        init_chan(c++, i, 1, ces++);
-                        ces %= 0xffff;
-                        init_chan(c++, i, 0, ces++);
-                        ces %= 0xffff;
-                }
-        printk(KERN_INFO "channels %d\n", chancount);
-        return (chancount);
-
-}
-
-static void
-release_is(int chan)
-{
-        struct PStack  *st = &chanlist[chan].is;
-
-        releasestack_isdnl2(st);
-        teles_rmlist(st->l1.hardware, st);
-        BufQueueRelease(&st->l2.i_queue);
-}
-
-void
-CallcFreeChan(void)
-{
-        int             i;
-
-        for (i = 0; i < chancount; i++)
-                release_is(i);
-        Sfree((void *) chanlist);
-}
-
-static void
-lldata_handler(struct PStack *st, int pr,
-               void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-        byte           *ptr;
-        int             size;
-        struct BufHeader *ibh = arg;
-
-        switch (pr) {
-          case (DL_DATA):
-                  if (chanp->data_open) {
-                          ptr = DATAPTR(ibh);
-                          ptr += chanp->ds.l2.ihsize;
-                          size = ibh->datasize - chanp->ds.l2.ihsize;
-                          iif.rcvcallb(drid, chanp->chan, ptr, size);
-                  }
-                  BufPoolRelease(ibh);
-                  break;
-          default:
-                  printk(KERN_WARNING "lldata_handler unknown primitive\n");
-                  break;
-        }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr,
-                struct BufHeader *ibh)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-        byte           *ptr;
-
-        switch (pr) {
-          case (PH_DATA):
-                  if (chanp->data_open) {
-                          ptr = DATAPTR(ibh);
-                          iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
-                  }
-                  BufPoolRelease(ibh);
-                  break;
-          default:
-                  printk(KERN_WARNING "lltrans_handler unknown primitive\n");
-                  break;
-        }
-}
-
-static void
-ll_writewakeup(struct PStack *st)
-{
-        struct Channel *chanp = st->l4.userdata;
-        isdn_ctrl       ic;
-
-        ic.driver = drid;
-        ic.command = ISDN_STAT_BSENT;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static int
-init_ds(int chan, int incoming)
-{
-        struct PStack  *st = &(chanlist[chan].ds);
-        struct IsdnCardState *sp = (struct IsdnCardState *)
-        chanlist[chan].is.l1.hardware;
-        struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
-        char            tmp[128];
-
-        st->l1.hardware = sp;
-
-        hsp->mode = 2;
-        hsp->transbufsize = 4000;
-
-        if (setstack_hscx(st, hsp))
-                return (-1);
-
-        st->l2.extended = 0;
-        st->l2.laptype = LAPB;
-        st->l2.orig = !incoming;
-        st->l2.t200 = 1000;        /* 1000 milliseconds */
-        st->l2.window = 7;
-        st->l2.n200 = 4;           /* try 4 times       */
-        st->l2.t203 = 5000;        /* 5000 milliseconds */
-
-        st->l2.debug = 0xff;
-        st->l3.debug = 0xff;
-        switch (chanlist[chan].l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  sprintf(tmp, "Channel %d x.75", chan);
-                  setstack_isdnl2(st, tmp);
-                  st->l2.l2l3 = lldata_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l2.l2man = dcc_l2man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = NULL;
-                  st->l4.l2writewakeup = ll_writewakeup;
-                  st->l2.l2m.debug = debugflags & 16;
-                  st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-                  st->l1.hscxmode = 2;        /* Packet-Mode ? */
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-                  st->l1.l1l2 = lltrans_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = ll_writewakeup;
-                  st->l1.hscxmode = 2;
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-          case (ISDN_PROTO_L2_TRANS):
-                  st->l1.l1l2 = lltrans_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = ll_writewakeup;
-                  st->l1.hscxmode = 1;
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-        }
-
-        return (0);
-
-}
-
-static void
-channel_report(int i)
-{
-}
-
-static void
-command_debug(struct Channel *chanp, char *s)
-{
-        char            tmp[64], tm[32];
-
-        jiftime(tm, jiffies);
-        sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
-        teles_putstatus(tmp);
-}
-
-static void
-distr_debug(void)
-{
-        int             i;
-
-        for (i = 0; i < chancount; i++) {
-                chanlist[i].debug = debugflags & 1;
-                chanlist[i].fi.debug = debugflags & 2;
-                chanlist[i].is.l2.l2m.debug = debugflags & 8;
-                chanlist[i].ds.l2.l2m.debug = debugflags & 16;
-        }
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp) {
-                        cards[i].sp->dlogflag = debugflags & 4;
-                        cards[i].sp->debug = debugflags & 32;
-                }
-}
-
-int
-teles_command(isdn_ctrl * ic)
-{
-        struct Channel *chanp;
-        char            tmp[64];
-        int             i;
-        unsigned int    num;
-
-        switch (ic->command) {
-          case (ISDN_CMD_SETEAZ):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "SETEAZ");
-                  return (0);
-          case (ISDN_CMD_DIAL):
-                  chanp = chanlist + (ic->arg & 0xff);
-                  if (chanp->debug & 1) {
-		  	  sprintf(tmp, "DIAL %s -> %s (%d,%d)",
-				ic->parm.setup.eazmsn, ic->parm.setup.phone,
-				ic->parm.setup.si1, ic->parm.setup.si2);
-                          command_debug(chanp, tmp);
-                  }
-                  FsmEvent(&chanp->fi, EV_DIAL, ic);
-                  return (0);
-          case (ISDN_CMD_ACCEPTB):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "ACCEPTB");
-                  FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
-                  break;
-          case (ISDN_CMD_ACCEPTD):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "ACCEPTD");
-                  FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
-                  break;
-          case (ISDN_CMD_HANGUP):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "HANGUP");
-                  FsmEvent(&chanp->fi, EV_HANGUP, NULL);
-                  break;
-          case (ISDN_CMD_SUSPEND):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "SUSPEND %s", ic->parm.num);
-                          command_debug(chanp, tmp);
-                  }
-                 FsmEvent(&chanp->fi, EV_SUSPEND, ic);
-                  break;
-          case (ISDN_CMD_RESUME):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "RESUME %s", ic->parm.num);
-                          command_debug(chanp, tmp);
-                  }
-                  FsmEvent(&chanp->fi, EV_RESUME, ic);
-                  break;
-          case (ISDN_CMD_LOCK):
-                  teles_mod_inc_use_count();
-                  break;
-          case (ISDN_CMD_UNLOCK):
-                  teles_mod_dec_use_count();
-                  break;
-          case (ISDN_CMD_IOCTL):
-                  switch (ic->arg) {
-                    case (0):
-                            for (i = 0; i < nrcards; i++)
-                                    if (cards[i].sp)
-                                            teles_reportcard(i);
-                            for (i = 0; i < chancount; i++)
-                                    channel_report(i);
-                            break;
-                    case (1):
-                            debugflags = *(unsigned int *) ic->parm.num;
-                            distr_debug();
-                            sprintf(tmp, "debugging flags set to %x\n", debugflags);
-                            teles_putstatus(tmp);
-			    printk(KERN_DEBUG "%s", tmp);
-                            break;
-                    case (2):
-                            num = *(unsigned int *) ic->parm.num;
-                            i = num >> 8;
-                            if (i >= chancount)
-                                    break;
-                            chanp = chanlist + i;
-                            chanp->impair = num & 0xff;
-                            if (chanp->debug & 1) {
-                                    sprintf(tmp, "IMPAIR %x", chanp->impair);
-                                    command_debug(chanp, tmp);
-                            }
-                            break;
-                  }
-                  break;
-          case (ISDN_CMD_SETL2):
-                  chanp = chanlist + (ic->arg & 0xff);
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
-                          command_debug(chanp, tmp);
-                  }
-                  chanp->l2_protocol = ic->arg >> 8;
-                  break;
-          default:
-                  break;
-        }
-
-        return (0);
-}
-
-int
-teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
-{
-        struct Channel *chanp = chanlist + chan;
-        struct PStack  *st = &chanp->ds;
-        struct BufHeader *ibh;
-        int             err, i;
-        byte           *ptr;
-
-	if (!chanp->data_open) {
-		printk(KERN_DEBUG "teles_writebuf: channel not open\n");
-		return -EIO;
-	}
-	
-        err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
-        if (err)
-                /* Must return 0 here, since this is not an error
-                 * but a temporary lack of resources.
-                 */
-                return 0;
-
-        ptr = DATAPTR(ibh);
-        if (chanp->lc_b.l2_establish)
-                i = st->l2.ihsize;
-        else
-                i = 0;
-
-        if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
-                printk(KERN_WARNING "teles_writebuf: packet too large!\n");
-                return (-EINVAL);
-        }
-
-        ptr += i;
-
-        if (user)
-                copy_from_user(ptr, buf, count);
-        else
-                memcpy(ptr, buf, count);
-        ibh->datasize = count + i;
-
-        if (chanp->data_open) {
-                if (chanp->lc_b.l2_establish)
-                        chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
-                else
-                        chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
-                return (count);
-        } else {
-                BufPoolRelease(ibh);
-                return (0);
-        }
-
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- v2.1.36/linux/drivers/isdn/teles/card.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/card.c	Wed Dec 31 16:00:00 1969
@@ -1,1900 +0,0 @@
-/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
- *
- * card.c     low level stuff for the Teles S0 isdn card
- * 
- * Author     Jan den Ouden
- * 
- * Beat Doebeli         log all D channel traffic
- * 
- * $Log: card.c,v $
- * Revision 1.16  1996/10/22 23:14:16  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.15  1996/09/29 19:41:56  fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.14  1996/09/23 01:53:49  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.13  1996/07/18 11:21:24  jdenoud
- * Use small buffers for incoming audio data
- *
- * Revision 1.12  1996/06/24 17:16:52  fritz
- * Added check for misconfigured membase.
- *
- * Revision 1.11  1996/06/14 03:30:37  fritz
- * Added recovery from EXIR 40 interrupt.
- * Some cleanup.
- *
- * Revision 1.10  1996/06/11 14:57:20  hipp
- * minor changes to ensure, that SKBs are sent in the right order
- *
- * Revision 1.9  1996/06/06 14:42:09  fritz
- * Bugfix: forgot hsp-> in last change.
- *
- * Revision 1.7  1996/05/31 01:02:21  fritz
- * Cosmetic changes.
- *
- * Revision 1.6  1996/05/26 14:58:10  fritz
- * Bugfix: Did not show port correctly, when no card found.
- *
- * Revision 1.5  1996/05/17 03:45:02  fritz
- * Made error messages more clearly.
- * Bugfix: Only 31 bytes of 32-byte audio frames
- *         have been transfered to upper layers.
- *
- * Revision 1.4  1996/05/06 10:17:57  fritz
- * Added voice-send stuff
- *  (Not reporting EXIR when in voice-mode, since it's normal).
- *
- * Revision 1.3  1996/04/30 22:02:40  isdn4dev
- * Bugfixes for 16.3
- *     -improved IO allocation
- *     -fix second B channel problem
- *     -correct ph_command patch
- *
- * Revision 1.2  1996/04/30 10:00:59  fritz
- * Bugfix: Added ph_command(8) for 16.3.
- * Bugfix: Ports did not get registered correctly
- *         when using a 16.3.
- *         Started voice support.
- *         Some experimental changes of waitforXFW().
- *
- * Revision 1.1  1996/04/13 10:22:42  fritz
- * Initial revision
- *
- *
- */
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-
-#undef DCHAN_VERBOSE
-
-extern void     tei_handler(struct PStack *st, byte pr,
-			    struct BufHeader *ibh);
-extern struct   IsdnCard cards[];
-extern int      nrcards;
-
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline   byte
-readisac_0(byte * cardm, byte offset)
-{
-	return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline   byte
-readisac_3(int iobase, byte offset)
-{
-        return (bytein(iobase - 0x420 + offset));
-}
-
-#define READISAC(mbase,ibase,ofs) \
-        ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
-
-static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
-{
-	writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline void
-writeisac_3(int iobase, byte offset, byte value)
-{
-	byteout(iobase - 0x420 + offset, value);
-}
-
-#define WRITEISAC(mbase,ibase,ofs,val) \
-        ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
-
-static inline void
-readisac_s(int iobase, byte offset, byte * dest, int count)
-{
-	insb(iobase - 0x420 + offset, dest, count);
-}
-
-static inline void
-writeisac_s(int iobase, byte offset, byte * src, int count)
-{
-	outsb(iobase - 0x420 + offset, src, count);
-}
-
-static inline   byte
-readhscx_0(byte * base, byte hscx, byte offset)
-{
-	return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
-			  ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline   byte
-readhscx_3(int iobase, byte hscx, byte offset)
-{
-	return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
-}
-
-#define READHSCX(mbase,ibase,hscx,ofs) \
-        ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
-
-static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
-{
-	writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
-		   ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline void
-writehscx_3(int iobase, byte hscx, byte offset, byte data)
-{
-	byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
-}
-
-static inline void
-readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
-{
-	insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
-}
-
-static inline void
-writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
-{
-	outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
-}
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-
-#define ISAC_RBCH 0x2a
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIX0 0x31
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void
-waitforCEC_0(byte * base, byte hscx)
-{
-	long            to = 10;
-
-	while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforCEC_3(int iobase, byte hscx)
-{
-	long            to = 10;
-
-	while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforXFW_0(byte * base, byte hscx)
-{
-	long            to = 20;
-
-	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-waitforXFW_3(int iobase, byte hscx)
-{
-	long            to = 20;
-
-	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	waitforCEC_0(base, hscx);
-	writehscx_0(base, hscx, HSCX_CMDR, data);
-	restore_flags(flags);
-}
-
-static inline void
-writehscxCMDR_3(int iobase, byte hscx, byte data)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	waitforCEC_3(iobase, hscx);
-	writehscx_3(iobase, hscx, HSCX_CMDR, data);
-	restore_flags(flags);
-}
-
-#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
-        ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
-
-/*
- * fast interrupt here
- */
-
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE    2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
-
-void
-teles_hscxreport(struct IsdnCardState *sp, int hscx)
-{
-        printk(KERN_DEBUG "HSCX %d\n", hscx);
-        if (sp->membase) {
-                printk(KERN_DEBUG "  ISTA %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_EXIR));
-        } else {
-                printk(KERN_DEBUG "  ISTA %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_EXIR));
-        }
-}
-
-void
-teles_report(struct IsdnCardState *sp)
-{
-	printk(KERN_DEBUG "ISAC\n");
-        if (sp->membase) {
-               printk(KERN_DEBUG "  ISTA %x\n", readisac_0(sp->membase,
-                                                            ISAC_ISTA));
-               printk(KERN_DEBUG "  STAR %x\n", readisac_0(sp->membase,
-                                                           ISAC_STAR));
-               printk(KERN_DEBUG "  EXIR %x\n", readisac_0(sp->membase,
-                                                           ISAC_EXIR));
-        } else {
-                printk(KERN_DEBUG "  ISTA %x\n", readisac_3(sp->iobase,
-                                                          ISAC_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readisac_3(sp->iobase,
-                                                          ISAC_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readisac_3(sp->iobase,
-                                                          ISAC_EXIR));
-        }
-	teles_hscxreport(sp, 0);
-	teles_hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
-	hsp->event |= 1 << event;
-	queue_task_irq_off(&hsp->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
-{
-	byte             *ptr;
-	struct BufHeader *ibh = hsp->rcvibh;
-
-	if (hsp->sp->debug)
-		printk(KERN_DEBUG "hscx_empty_fifo\n");
-
-	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
-					      HSCX_RBUF_BPPS)) {
-		printk(KERN_WARNING
-                       "hscx_empty_fifo: incoming packet too large\n");
-		WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
-		return;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += hsp->rcvptr;
-
-	hsp->rcvptr += count;
-        if (hsp->membase) {
-                while (count--)
-                        *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
-                writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
-        } else {
-                readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
-                writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
-        }
-}
-
-static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
-	struct BufHeader *ibh;
-	int              more, count;
-	byte             *ptr;
-
-	if (hsp->sp->debug)
-		printk(KERN_DEBUG "hscx_fill_fifo\n");
-
-	ibh = hsp->xmtibh;
-	if (!ibh)
-                return;
-
-	count = ibh->datasize - hsp->sendptr;
-	if (count <= 0)
-                return;
-
-	more = (hsp->mode == 1)?1:0;
-	if (count > 32) {
-		more = !0;
-		count = 32;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += hsp->sendptr;
-	hsp->sendptr += count;
-
-#ifdef BCHAN_VERBOSE
-        {
-                int i;
-                printk(KERN_DEBUG "hscx_fill_fifo ");
-                for (i = 0; i < count; i++)
-                        printk(" %2x", ptr[i]);
-                printk("\n");
-        }
-#endif
-        if (hsp->membase) {
-                waitforXFW_0(hsp->membase, hsp->hscx);
-                while (count--)
-                        writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
-                writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
-        } else {
-                waitforXFW_3(hsp->iobase, hsp->hscx);
-                writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
-                writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
-        }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
-{
-	byte             r;
-	struct HscxState *hsp = sp->hs + hscx;
-	int              count, err;
-
-	if (!hsp->init)
-		return;
-
-	if (val & 0x80) {	/* RME */
-
-		r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
-		if ((r & 0xf0) != 0xa0) {
-			if (!r & 0x80)
-				printk(KERN_WARNING
-                                       "Teles: HSCX invalid frame\n");
-			if ((r & 0x40) && hsp->mode)
-				printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
-			if (!r & 0x20)
-				printk(KERN_WARNING "Teles: HSCX CRC error\n");
-			if (hsp->rcvibh)
-				BufPoolRelease(hsp->rcvibh);
-			hsp->rcvibh = NULL;
-			WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
-                                       0x80);
-			goto afterRME;
-		}
-		if (!hsp->rcvibh)
-			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
-                                       GFP_ATOMIC, (void *) 1, 1)) {
-				printk(KERN_WARNING
-                                       "HSCX RME out of buffers at %ld\n",
-                                       jiffies);
-				WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x80);
-				goto afterRME;
-			} else
-				hsp->rcvptr = 0;
-
-		count = READHSCX(hsp->membase, sp->iobase, hsp->hscx,
-                                 HSCX_RBCL) & 0x1f;
-		if (count == 0)
-			count = 32;
-		hscx_empty_fifo(hsp, count);
-		hsp->rcvibh->datasize = hsp->rcvptr - 1;
-		BufQueueLink(&hsp->rq, hsp->rcvibh);
-		hsp->rcvibh = NULL;
-		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-	}
-      afterRME:
-	if (val & 0x40) {	/* RPF */
-		if (!hsp->rcvibh) {
-			if (hsp->mode == 1)
-				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
-					GFP_ATOMIC, (void *)1, 2);
-			else
-				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
-					GFP_ATOMIC, (void *)1, 2);
-			
-			if (err) {
-				printk(KERN_WARNING
-                                       "HSCX RPF out of buffers at %ld\n",
-                                       jiffies);
-				WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x80);
-				goto afterRPF;
-			} else
-				hsp->rcvptr = 0;
-		}
-		
-		hscx_empty_fifo(hsp, 32);
-                if (hsp->mode == 1) {
-                        /* receive audio data */
-                        hsp->rcvibh->datasize = hsp->rcvptr;
-                        BufQueueLink(&hsp->rq, hsp->rcvibh);
-                        hsp->rcvibh = NULL;
-                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-                }
-                
-	}
-      afterRPF:
-	if (val & 0x10) {	/* XPR */
-		if (hsp->xmtibh)
-			if (hsp->xmtibh->datasize > hsp->sendptr) {
-				hscx_fill_fifo(hsp);
-				goto afterXPR;
-			} else {
-				if (hsp->releasebuf)
-					BufPoolRelease(hsp->xmtibh);
-				hsp->sendptr = 0;
-				if (hsp->st->l4.l1writewakeup)
-					hsp->st->l4.l1writewakeup(hsp->st);
-				hsp->xmtibh = NULL;
-			}
-		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
-			hsp->releasebuf = !0;
-			hscx_fill_fifo(hsp);
-		} else
-			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-	}
-      afterXPR:
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
-	sp->event |= 1 << event;
-	queue_task_irq_off(&sp->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-empty_fifo(struct IsdnCardState *sp, int count)
-{
-	byte             *ptr;
-	struct BufHeader *ibh = sp->rcvibh;
-
-	if (sp->debug)
-		printk(KERN_DEBUG "empty_fifo\n");
-
-	if (sp->rcvptr >= 3072) {
-		printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
-		return;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += sp->rcvptr;
-	sp->rcvptr += count;
-
-        if (sp->membase) {
-#ifdef DCHAN_VERBOSE
-                printk(KERN_DEBUG "empty_fifo ");
-                while (count--) {
-                        *ptr = readisac_0(sp->membase, 0x0);
-                        printk("%2x ", *ptr);
-                        ptr++;
-                }
-                printk("\n");
-#else
-                while (count--)
-                        *ptr++ = readisac_0(sp->membase, 0x0);
-#endif
-                writeisac_0(sp->membase, ISAC_CMDR, 0x80);
-        } else {
-#ifdef DCHAN_VERBOSE
-                int i;
-                printk(KERN_DEBUG "empty_fifo ");
-                readisac_s(sp->iobase, 0x3e, ptr, count);
-                for (i = 0; i < count; i++)
-                        printk("%2x ", ptr[i]);
-                printk("\n");
-#else
-                readisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
-                writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
-        }
-}
-
-static void
-fill_fifo(struct IsdnCardState *sp)
-{
-	struct BufHeader *ibh;
-	int              count, more;
-	byte             *ptr;
-
-	if (sp->debug)
-		printk(KERN_DEBUG "fill_fifo\n");
-
-	ibh = sp->xmtibh;
-	if (!ibh)
-		return;
-
-	count = ibh->datasize - sp->sendptr;
-	if (count <= 0)
-		return;
-	if (count >= 3072)
-		return;
-
-	more = 0;
-	if (count > 32) {
-		more = !0;
-		count = 32;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += sp->sendptr;
-	sp->sendptr += count;
-
-        if (sp->membase) {
-#ifdef DCHAN_VERBOSE
-                printk(KERN_DEBUG "fill_fifo ");
-                while (count--) {
-                        writeisac_0(sp->membase, 0x0, *ptr);
-                        printk("%2x ", *ptr);
-                        ptr++;
-                }
-                printk("\n");
-#else
-                while (count--)
-                        writeisac_0(sp->membase, 0x0, *ptr++);
-#endif
-                writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
-        } else {
-#ifdef DCHAN_VERBOSE
-                int i;
-                writeisac_s(sp->iobase, 0x3e, ptr, count);
-                printk(KERN_DEBUG "fill_fifo ");
-                for (i = 0; i < count; i++)
-                        printk("%2x ", ptr[i]);
-                printk("\n");
-#else
-                writeisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
-                writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
-        }
-}
-
-static int
-act_wanted(struct IsdnCardState *sp)
-{
-	struct PStack  *st;
-
-	st = sp->stlist;
-	while (st)
-		if (st->l1.act_state)
-			return (!0);
-		else
-			st = st->next;
-	return (0);
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
-	printk(KERN_DEBUG "ph_command %d\n", command);
-	WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_new_ph(struct IsdnCardState *sp)
-{
-	int             enq;
-
-	enq = act_wanted(sp);
-
-	switch (sp->ph_state) {
-	  case (0):
-	  case (6):
-		  if (enq)
-			  ph_command(sp, 0);
-		  else
-			  ph_command(sp, 15);
-		  break;
-	  case (7):
-		  if (enq)
-			  ph_command(sp, 9);
-		  break;
-	  case (12):
-	          ph_command(sp, 8);
-		  sp->ph_active = 5;
-		  isac_sched_event(sp, ISAC_PHCHANGE);
-		  if (!sp->xmtibh)
-			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
-				  sp->sendptr = 0;
-		  if (sp->xmtibh)
-			  fill_fifo(sp);
-		  break;
-	  case (13):
-	          ph_command(sp, 9);
-		  sp->ph_active = 5;
-		  isac_sched_event(sp, ISAC_PHCHANGE);
-		  if (!sp->xmtibh)
-			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
-				  sp->sendptr = 0;
-		  if (sp->xmtibh)
-			  fill_fifo(sp);
-		  break;
-	  case (4):
-	  case (8):
-		  break;
-	  default:
-		  sp->ph_active = 0;
-		  break;
-	}
-}
-
-static void
-teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
-	byte                 val, r, exval;
-	struct IsdnCardState *sp;
-	unsigned int         count;
-	struct HscxState     *hsp;
-
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
-
-	if (!sp) {
-		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
-		return;
-	}
-	val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
-
-	if (val & 0x01) {
-		hsp = sp->hs + 1;
-                exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
-                if (exval == 0x40) {
-                        if (hsp->mode == 1)
-                                hscx_fill_fifo(hsp);
-                        else {
-                                /* Here we lost an TX interrupt, so
-                                 * restart transmitting the whole frame.
-                                 */
-                                hsp->sendptr = 0;
-			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x01);
-                                printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
-                        }
-                } else
-                        printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
-	}
-	if (val & 0xf8) {
-		if (sp->debug)
-			printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
-		hscx_interrupt(sp, val, 1);
-	}
-	if (val & 0x02) {
-		hsp = sp->hs;
-                exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
-                if (exval == 0x40) {
-                        if (hsp->mode == 1)
-                                hscx_fill_fifo(hsp);
-                        else {
-                                /* Here we lost an TX interrupt, so
-                                 * restart transmitting the whole frame.
-                                 */
-                                hsp->sendptr = 0;
-			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x01);
-                                printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
-                        }
-                } else
-                        printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
-	}
-        if (val & 0x04) {
-                val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
-                if (sp->debug)
-                        printk(KERN_DEBUG "HSCX A interrupt %x\n",
-                               val);
-                hscx_interrupt(sp, val, 0);
-        }
-
-	val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
-
-	if (sp->debug)
-		printk(KERN_DEBUG "ISAC interrupt %x\n", val);
-
-	if (val & 0x80) {	/* RME */
-
-		r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
-		if ((r & 0x70) != 0x20) {
-			if (r & 0x40)
-				printk(KERN_WARNING "Teles: ISAC RDO\n");
-			if (!r & 0x20)
-				printk(KERN_WARNING "Teles: ISAC CRC error\n");
-			if (sp->rcvibh)
-				BufPoolRelease(sp->rcvibh);
-			sp->rcvibh = NULL;
-			WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
-			goto afterRME;
-		}
-		if (!sp->rcvibh)
-			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
-                                       GFP_ATOMIC,
-				       (void *) 1, 3)) {
-				printk(KERN_WARNING
-                                       "ISAC RME out of buffers!\n");
-				WRITEISAC(sp->membase, sp->iobase, 
-                                          ISAC_CMDR, 0x80);
-				goto afterRME;
-			} else
-				sp->rcvptr = 0;
-
-		count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
-		if (count == 0)
-			count = 32;
-		empty_fifo(sp, count);
-		sp->rcvibh->datasize = sp->rcvptr;
-		BufQueueLink(&(sp->rq), sp->rcvibh);
-		sp->rcvibh = NULL;
-		isac_sched_event(sp, ISAC_RCVBUFREADY);
-	}
-      afterRME:
-	if (val & 0x40) {	/* RPF */
-		if (!sp->rcvibh)
-			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
-                                       GFP_ATOMIC,
-				       (void *) 1, 4)) {
-				printk(KERN_WARNING
-                                       "ISAC RME out of buffers!\n");
-				WRITEISAC(sp->membase, sp->iobase,
-                                          ISAC_CMDR, 0x80);
-				goto afterRPF;
-			} else
-				sp->rcvptr = 0;
-		empty_fifo(sp, 32);
-	}
-      afterRPF:
-	if (val & 0x20) {
-	}
-	if (val & 0x10) {	/* XPR */
-		if (sp->xmtibh)
-			if (sp->xmtibh->datasize > sp->sendptr) {
-				fill_fifo(sp);
-				goto afterXPR;
-			} else {
-				if (sp->releasebuf)
-					BufPoolRelease(sp->xmtibh);
-				sp->xmtibh = NULL;
-				sp->sendptr = 0;
-			}
-		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
-			sp->releasebuf = !0;
-			fill_fifo(sp);
-		} else
-			isac_sched_event(sp, ISAC_XMTBUFREADY);
-	}
-      afterXPR:
-	if (val & 0x04) {	/* CISQ */
-		sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
-                                >> 2) & 0xf;
-		printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
-		isac_new_ph(sp);
-	}
-        if (sp->membase) {
-                writeisac_0(sp->membase, ISAC_MASK, 0xFF);
-                writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
-                writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
-                writeisac_0(sp->membase, ISAC_MASK, 0x0);
-                writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
-                writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
-        } else {
-                writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
-                writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
-                writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
-                writeisac_3(sp->iobase, ISAC_MASK, 0x0);
-                writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
-                writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
-        }
-}
-
-/*
- * soft interrupt
- */
-
-static void
-act_ivated(struct IsdnCardState *sp)
-{
-	struct PStack  *st;
-
-	st = sp->stlist;
-	while (st) {
-		if (st->l1.act_state == 1) {
-			st->l1.act_state = 2;
-			st->l1.l1man(st, PH_ACTIVATE, NULL);
-		}
-		st = st->next;
-	}
-}
-
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
-	if (sp->ph_active == 5)
-		act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
-{
-	struct PStack  *stptr;
-
-	if (sp->xmtibh)
-		return;
-
-	stptr = sp->stlist;
-	while (stptr != NULL)
-		if (stptr->l1.requestpull) {
-			stptr->l1.requestpull = 0;
-			stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
-			break;
-		} else
-			stptr = stptr->next;
-}
-
-static void
-process_rcv(struct IsdnCardState *sp)
-{
-	struct BufHeader *ibh, *cibh;
-	struct PStack    *stptr;
-	byte             *ptr;
-	int              found, broadc;
-	char             tmp[64];
-
-	while (!BufQueueUnlink(&ibh, &sp->rq)) {
-		stptr = sp->stlist;
-		ptr = DATAPTR(ibh);
-		broadc = (ptr[1] >> 1) == 127;
-
-		if (broadc && sp->dlogflag && (!(ptr[0] >> 2)))
-			dlogframe(sp, ptr + 3, ibh->datasize - 3,
-				  "Q.931 frame network->user broadcast");
-
-		if (broadc) {
-			while (stptr != NULL) {
-				if ((ptr[0] >> 2) == stptr->l2.sap)
-					if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
-							(void *) 1, 5)) {
-						memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
-						cibh->datasize = ibh->datasize;
-						stptr->l1.l1l2(stptr, PH_DATA, cibh);
-					} else
-						printk(KERN_WARNING "isdn broadcast buffer shortage\n");
-				stptr = stptr->next;
-			}
-			BufPoolRelease(ibh);
-		} else {
-			found = 0;
-			while (stptr != NULL)
-				if (((ptr[0] >> 2) == stptr->l2.sap) &&
-				    ((ptr[1] >> 1) == stptr->l2.tei)) {
-					stptr->l1.l1l2(stptr, PH_DATA, ibh);
-					found = !0;
-					break;
-				} else
-					stptr = stptr->next;
-			if (!found) {
-				/* BD 10.10.95
-				 * Print out D-Channel msg not processed
-				 * by isdn4linux
-                                 */
-
-				if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
-					sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1);
-					dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
-				}
-				BufPoolRelease(ibh);
-			}
-		}
-
-	}
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
-	if (!sp)
-		return;
-
-	if (clear_bit(ISAC_PHCHANGE, &sp->event))
-		process_new_ph(sp);
-	if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
-		process_rcv(sp);
-	if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
-		process_xmt(sp);
-}
-
-
-static void
-hscx_process_xmt(struct HscxState *hsp)
-{
-	struct PStack  *st = hsp->st;
-
-	if (hsp->xmtibh)
-		return;
-
-	if (st->l1.requestpull) {
-		st->l1.requestpull = 0;
-		st->l1.l1l2(st, PH_PULL_ACK, NULL);
-	}
-	if (!hsp->active)
-		if ((!hsp->xmtibh) && (!hsp->sq.head))
-			modehscx(hsp, 0, 0);
-}
-
-static void
-hscx_process_rcv(struct HscxState *hsp)
-{
-	struct BufHeader *ibh;
-
-#ifdef DEBUG_MAGIC
-	if (hsp->magic != 301270) {
-		printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
-		return;
-	}
-#endif
-	while (!BufQueueUnlink(&ibh, &hsp->rq)) {
-		hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
-	}
-}
-
-static void
-hscx_bh(struct HscxState *hsp)
-{
-
-	if (!hsp)
-		return;
-
-	if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
-		hscx_process_rcv(hsp);
-	if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
-		hscx_process_xmt(hsp);
-
-}
-
-/*
- * interrupt stuff ends here
- */
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
-	switch (sp->ph_active) {
-	  case (0):
-		  if (sp->ph_state == 6)
-			  ph_command(sp, 0);
-		  else
-			  ph_command(sp, 1);
-		  sp->ph_active = 1;
-		  break;
-	}
-}
-
-static void
-initisac(byte * cardmem, int iobase)
-{
-        if (cardmem) {
-                writeisac_0(cardmem, ISAC_MASK, 0xff);
-                writeisac_0(cardmem, ISAC_ADF2, 0x0);
-                writeisac_0(cardmem, ISAC_SPCR, 0xa);
-                writeisac_0(cardmem, ISAC_ADF1, 0x2);
-                writeisac_0(cardmem, ISAC_STCR, 0x70);
-                writeisac_0(cardmem, ISAC_MODE, 0xc9);
-                writeisac_0(cardmem, ISAC_CMDR, 0x41);
-                writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
-        } else {
-                writeisac_3(iobase, ISAC_MASK, 0xff);
-                writeisac_3(iobase, ISAC_ADF2, 0x80);
-                writeisac_3(iobase, ISAC_SQXR, 0x2f);
-                writeisac_3(iobase, ISAC_SPCR, 0x00);
-                writeisac_3(iobase, ISAC_ADF1, 0x02);
-                writeisac_3(iobase, ISAC_STCR, 0x70);
-                writeisac_3(iobase, ISAC_MODE, 0xc9);
-                writeisac_3(iobase, ISAC_TIMR, 0x00);
-                writeisac_3(iobase, ISAC_ADF1, 0x00);
-                writeisac_3(iobase, ISAC_CMDR, 0x41);
-                writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
-        }
-}
-
-static int
-checkcard(int cardnr)
-{
-	int             timout;
-	byte            cfval, val;
-	struct IsdnCard *card = cards + cardnr;
-
-        if (card->membase)
-                if ((unsigned long)card->membase < 0x10000) {
-                        (unsigned long)card->membase <<= 4;
-                        printk(KERN_INFO
-                               "Teles membase configured DOSish, assuming 0x%lx\n",
-                               (unsigned long)card->membase);
-                }
-        if (!card->iobase) {
-                if (card->membase) {
-                        printk(KERN_NOTICE
-                               "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
-                               (long) card->membase, card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                        printk(KERN_INFO "HSCX version A:%x B:%x\n",
-                               readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
-                               readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
-                }
-        } else {
-                switch (card->iobase) {
-                        case 0x180:
-                        case 0x280:
-                        case 0x380:
-                                card->iobase |= 0xc00;
-                                break;
-                }
-                if (card->membase) {  /* 16.0 */
-                	if (check_region(card->iobase, 8)) {
-                        	printk(KERN_WARNING
-                               		"teles: ports %x-%x already in use\n",
-                               		card->iobase,
-                               		card->iobase + 8 );
-                        	return -1;
-                	}
-                } else { /* 16.3 */
-                	if (check_region(card->iobase, 16)) {
-                        	printk(KERN_WARNING
-                               		"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase,
-                               		card->iobase + 16 );
-                        	return -1;
-                	}
-                	if (check_region((card->iobase - 0xc00) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0xc00,
-                               		card->iobase - 0xc00 + 32);
-                        	return -1;
-                        }
-                	if (check_region((card->iobase - 0x800) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0x800,
-                               		card->iobase - 0x800 + 32);
-                        	return -1;
-                        }
-                	if (check_region((card->iobase - 0x400) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0x400,
-                               		card->iobase - 0x400 + 32);
-                        	return -1;
-                        }
-                }
-                switch (card->interrupt) {
-                case 2:
-                        cfval = 0x00;
-                        break;
-                case 3:
-                        cfval = 0x02;
-                        break;
-                case 4:
-                        cfval = 0x04;
-                        break;
-                case 5:
-                        cfval = 0x06;
-                        break;
-                case 10:
-                        cfval = 0x08;
-                        break;
-                case 11:
-                        cfval = 0x0A;
-                        break;
-                case 12:
-                        cfval = 0x0C;
-                        break;
-                case 15:
-                        cfval = 0x0E;
-                        break;
-                default:
-                        cfval = 0x00;
-                        break;
-                }
-                if (card->membase) {
-                        cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
-                }   
-                if (bytein(card->iobase + 0) != 0x51) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 0,
-                                bytein(card->iobase + 0));
-                        return -2;
-                }
-                if (bytein(card->iobase + 1) != 0x93) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 1,
-                                bytein(card->iobase + 1));
-                        return -2;
-                }
-                val = bytein(card->iobase + 2);	/* 0x1e=without AB
-                                                 * 0x1f=with AB
-                                                 * 0x1c 16.3 ???
-                                                 */
-                if (val != 0x1c && val != 0x1e && val != 0x1f) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 2,
-                                bytein(card->iobase + 2));
-                        return -2;
-                }
-                if (card->membase) {  /* 16.0 */
-                        request_region(card->iobase, 8, "teles 16.0");
-                } else {
-                	request_region(card->iobase, 16, "teles 16.3");
-                	request_region(card->iobase - 0xC00, 32, "teles HSCX0");
-                	request_region(card->iobase - 0x800, 32, "teles HSCX1");
-                	request_region(card->iobase - 0x400, 32, "teles ISAC");
-                }
-                cli();
-                timout = jiffies + (HZ / 10) + 1;
-                byteout(card->iobase + 4, cfval);
-                sti();
-                while (jiffies <= timout);
-                
-                cli();
-                timout = jiffies + (HZ / 10) + 1;
-                byteout(card->iobase + 4, cfval | 1);
-                sti();
-                while (jiffies <= timout);
-                
-                if (card->membase)
-                        printk(KERN_NOTICE
-                               "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
-                               card->iobase, (long) card->membase,
-                               card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                else
-                        printk(KERN_NOTICE
-                               "Teles 16.3 found, io: %x irq: %d proto: %s\n",
-                               card->iobase, card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                printk(KERN_INFO "HSCX version A:%x B:%x\n",
-                       READHSCX(card->membase, card->iobase, 0,
-                                HSCX_VSTR) & 0xf,
-                       READHSCX(card->membase, card->iobase, 1,
-                                HSCX_VSTR) & 0xf);
-                
-        }
-        if (card->membase) {
-                cli();
-                timout = jiffies + (HZ / 5) + 1;
-                writeb(0, card->membase + 0x80);
-                sti();
-                while (jiffies <= timout);
-                
-                cli();
-                writeb(1, card->membase + 0x80);
-                timout = jiffies + (HZ / 5) + 1;
-                sti();
-                while (jiffies <= timout);
-        }
-	return (0);
-}
-
-void
-modehscx(struct HscxState *hs, int mode,
-	 int ichan)
-{
-	struct IsdnCardState *sp = hs->sp;
-	int             hscx = hs->hscx;
-
-	printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
-	       hscx, mode, ichan);
-
-        hs->mode = mode;
-        if (sp->membase) {
-                /* What's that ??? KKeil */
-		if (hscx == 0)
-			ichan = 1 - ichan;	/* raar maar waar... */
-                writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
-                writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
-
-                switch (mode) {
-                case (0):
-                        writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                        writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
-                        writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
-                        writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                        writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
-                        break;
-                case (1):
-                        if (ichan == 0) {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
-                        writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                case (2):
-                        if (ichan == 0) {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
-                        writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                }
-                writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
-        } else {
-                writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
-                writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
-                writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
-                
-                switch (mode) {
-                case (0):
-                        writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                        writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
-                        writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
-                        writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                        writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
-                        break;
-                case (1):
-                        if (ichan == 0) {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
-                        writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                case (2):
-                        if (ichan == 0) {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
-                        writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                }
-                writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
-        }
-}
-
-void
-teles_addlist(struct IsdnCardState *sp,
-	      struct PStack *st)
-{
-	st->next = sp->stlist;
-	sp->stlist = st;
-}
-
-void
-teles_rmlist(struct IsdnCardState *sp,
-	     struct PStack *st)
-{
-	struct PStack  *p;
-
-	if (sp->stlist == st)
-		sp->stlist = st->next;
-	else {
-		p = sp->stlist;
-		while (p)
-			if (p->next == st) {
-				p->next = st->next;
-				return;
-			} else
-				p = p->next;
-	}
-}
-
-
-static void
-teles_l2l1(struct PStack *st, int pr,
-	   struct BufHeader *ibh)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-
-
-	switch (pr) {
-	  case (PH_DATA):
-		  if (sp->xmtibh)
-			  BufQueueLink(&sp->sq, ibh);
-		  else {
-			  sp->xmtibh = ibh;
-			  sp->sendptr = 0;
-			  sp->releasebuf = !0;
-			  fill_fifo(sp);
-		  }
-		  break;
-	  case (PH_DATA_PULLED):
-		  if (sp->xmtibh) {
-			  printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
-			  break;
-		  }
-		  sp->xmtibh = ibh;
-		  sp->sendptr = 0;
-		  sp->releasebuf = 0;
-		  fill_fifo(sp);
-		  break;
-	  case (PH_REQUEST_PULL):
-		  if (!sp->xmtibh) {
-			  st->l1.requestpull = 0;
-			  st->l1.l1l2(st, PH_PULL_ACK, NULL);
-		  } else
-			  st->l1.requestpull = !0;
-		  break;
-	}
-}
-
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
-	struct PStack  *st = sp->stlist;
-
-	while (st) {
-		if (st->l1.act_state)
-			return;
-		st = st->next;
-	}
-	sp->ph_active = 0;
-}
-
-static void
-teles_manl1(struct PStack *st, int pr,
-	    void *arg)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	long            flags;
-
-	switch (pr) {
-	  case (PH_ACTIVATE):
-		  save_flags(flags);
-		  cli();
-		  if (sp->ph_active == 5) {
-			  st->l1.act_state = 2;
-			  restore_flags(flags);
-			  st->l1.l1man(st, PH_ACTIVATE, NULL);
-		  } else {
-			  st->l1.act_state = 1;
-			  if (sp->ph_active == 0)
-				  restart_ph(sp);
-			  restore_flags(flags);
-		  }
-		  break;
-	  case (PH_DEACTIVATE):
-		  st->l1.act_state = 0;
-		  check_ph_act(sp);
-		  break;
-	}
-}
-
-static void
-teles_l2l1discardq(struct PStack *st, int pr,
-		   void *heldby, int releasetoo)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-
-#ifdef DEBUG_MAGIC
-	if (sp->magic != 301271) {
-		printk(KERN_DEBUG "isac_discardq magic not 301271\n");
-		return;
-	}
-#endif
-
-	BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
-}
-
-void
-setstack_teles(struct PStack *st, struct IsdnCardState *sp)
-{
-	st->l1.hardware = sp;
-	st->l1.sbufpool = &(sp->sbufpool);
-	st->l1.rbufpool = &(sp->rbufpool);
-	st->l1.smallpool = &(sp->smallpool);
-	st->protocol = sp->teistack->protocol;
-
-	setstack_tei(st);
-
-	st->l1.stlistp = &(sp->stlist);
-	st->l1.act_state = 0;
-	st->l2.l2l1 = teles_l2l1;
-	st->l2.l2l1discardq = teles_l2l1discardq;
-	st->ma.manl1 = teles_manl1;
-	st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
-	       int hscx)
-{
-	struct HscxState *hsp = sp->hs + hscx;
-
-	hsp->sp = sp;
-	hsp->hscx = hscx;
-	hsp->membase = sp->membase;
-	hsp->iobase = sp->iobase;
-
-	hsp->tqueue.next = 0;
-	hsp->tqueue.sync = 0;
-	hsp->tqueue.routine = (void *) (void *) hscx_bh;
-	hsp->tqueue.data = hsp;
-
-	hsp->inuse = 0;
-	hsp->init = 0;
-	hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
-	hsp->magic = 301270;
-#endif
-}
-
-void
-initcard(int cardnr)
-{
-	struct IsdnCardState *sp;
-	struct IsdnCard *card = cards + cardnr;
-
-	sp = (struct IsdnCardState *)
-	    Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
-		    "struct IsdnCardState");
-
-	sp->membase = card->membase;
-	sp->iobase = card->iobase;
-	sp->cardnr = cardnr;
-
-	BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
-		    ISAC_SBUF_MAXPAGES);
-	BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
-		    ISAC_RBUF_MAXPAGES);
-	BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
-		    ISAC_SMALLBUF_MAXPAGES);
-
-	sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
-
-	initisac(card->membase, card->iobase);
-
-	sp->rcvibh = NULL;
-	sp->rcvptr = 0;
-	sp->xmtibh = NULL;
-	sp->sendptr = 0;
-	sp->event = 0;
-	sp->tqueue.next = 0;
-	sp->tqueue.sync = 0;
-	sp->tqueue.routine = (void *) (void *) isac_bh;
-	sp->tqueue.data = sp;
-
-	BufQueueInit(&sp->rq);
-	BufQueueInit(&sp->sq);
-
-	sp->stlist = NULL;
-
-	sp->ph_active = 0;
-
-	sp->dlogflag = 0;
-	sp->debug = 0;
-
-	sp->releasebuf = 0;
-#ifdef DEBUG_MAGIC
-	sp->magic = 301271;
-#endif
-
-	cards[sp->cardnr].sp = sp;
-
-	init_hscxstate(sp, 0);
-	init_hscxstate(sp, 1);
-
-	modehscx(sp->hs, 0, 0);
-	modehscx(sp->hs + 1, 0, 0);
-
-	WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
-}
-
-static int
-get_irq(int cardnr)
-{
-	struct IsdnCard *card = cards + cardnr;
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	if (request_irq(card->interrupt, &teles_interrupt,
-			SA_INTERRUPT, "teles", NULL)) {
-		printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
-                       card->interrupt);
-		restore_flags(flags);
-		return (!0);
-	}
-	irq2dev_map[card->interrupt] = (void *) card->sp;
-	restore_flags(flags);
-	return (0);
-}
-
-static void
-release_irq(int cardnr)
-{
-	struct	IsdnCard *card = cards + cardnr;
-
-	irq2dev_map[card->interrupt] = NULL;
-	free_irq(card->interrupt, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
-	modehscx(hs, 0, 0);
-	hs->inuse = 0;
-
-	if (hs->init) {
-		BufPoolFree(&hs->smallpool);
-		BufPoolFree(&hs->rbufpool);
-		BufPoolFree(&hs->sbufpool);
-	}
-	hs->init = 0;
-}
-
-void
-closecard(int cardnr)
-{
-	struct IsdnCardState *sp = cards[cardnr].sp;
-
-	cards[cardnr].sp = NULL;
-
-	Sfree(sp->dlogspace);
-
-	BufPoolFree(&sp->smallpool);
-	BufPoolFree(&sp->rbufpool);
-	BufPoolFree(&sp->sbufpool);
-
-	close_hscxstate(sp->hs + 1);
-	close_hscxstate(sp->hs);
-
-	if (cards[cardnr].iobase)
-        	if (cards[cardnr].membase) {  /* 16.0 */
-			release_region(cards[cardnr].iobase, 8);
-        	} else {
-			release_region(cards[cardnr].iobase, 16);
-                	release_region(cards[cardnr].iobase - 0xC00, 32);
-                	release_region(cards[cardnr].iobase - 0x800, 32);
-                	release_region(cards[cardnr].iobase - 0x400, 32);
-                }
-
-	Sfree((void *) sp);
-}
-
-void
-teles_shiftcards(int idx)
-{
-        int i;
-
-        for (i = idx; i < 15; i++)
-                memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
-}
-
-int
-teles_inithardware(void)
-{
-        int             foundcards = 0;
-	int             i = 0;
-
-	while (i < nrcards) {
-                if (!cards[i].protocol)
-                        break;
-		switch (checkcard(i)) {
-		  case (0):
-			  initcard(i);
-			  if (get_irq(i)) {
-				  closecard(i);
-                                  teles_shiftcards(i);
-                          } else {
-                                  foundcards++;
-                                  i++;
-                          }
-			  break;
-		  case (-1):
-                          teles_shiftcards(i);
-			  break;
-		  case (-2):
-			  release_region(cards[i].iobase, 8);
-			  printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
-                          teles_shiftcards(i);
-			  break;
-		}
-        }
-        return foundcards;
-}
-
-void
-teles_closehardware(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp) {
-			release_irq(i);
-			closecard(i);
-		}
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr,
-	  struct BufHeader *ibh)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-	long flags;
-
-	switch (pr) {
-                case (PH_DATA):
-			save_flags(flags);
-			cli();
-                        if (hsp->xmtibh) {
-                                BufQueueLink(&hsp->sq, ibh);
-				restore_flags(flags);
-			}
-                        else {
-				restore_flags(flags);
-                                hsp->xmtibh = ibh;
-                                hsp->sendptr = 0;
-                                hsp->releasebuf = !0;
-                                hscx_fill_fifo(hsp);
-                        }
-                        break;
-                case (PH_DATA_PULLED):
-                        if (hsp->xmtibh) {
-                                printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
-                                break;
-                        }
-                        hsp->xmtibh = ibh;
-                        hsp->sendptr = 0;
-                        hsp->releasebuf = 0;
-                        hscx_fill_fifo(hsp);
-                        break;
-                case (PH_REQUEST_PULL):
-                        if (!hsp->xmtibh) {
-                                st->l1.requestpull = 0;
-                                st->l1.l1l2(st, PH_PULL_ACK, NULL);
-                        } else
-                                st->l1.requestpull = !0;
-                        break;
-	}
-        
-}
-
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
-		  int releasetoo)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-#ifdef DEBUG_MAGIC
-	if (hsp->magic != 301270) {
-		printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
-		return;
-	}
-#endif
-
-	BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
-	       int hscx)
-{
-	struct HscxState *hsp = sp->hs + hscx;
-
-	if (!hsp->init) {
-		BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
-			    HSCX_SBUF_MAXPAGES);
-		BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
-			    HSCX_RBUF_MAXPAGES);
-		BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
-			    HSCX_SMALLBUF_MAXPAGES);
-	}
-	hsp->init = !0;
-
-	BufQueueInit(&hsp->rq);
-	BufQueueInit(&hsp->sq);
-
-	hsp->releasebuf = 0;
-	hsp->rcvibh = NULL;
-	hsp->xmtibh = NULL;
-	hsp->rcvptr = 0;
-	hsp->sendptr = 0;
-	hsp->event = 0;
-	return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
-	   void *arg)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-	switch (pr) {
-	  case (PH_ACTIVATE):
-		  hsp->active = !0;
-		  modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
-		  st->l1.l1man(st, PH_ACTIVATE, NULL);
-		  break;
-	  case (PH_DEACTIVATE):
-		  if (!hsp->xmtibh)
-			  modehscx(hsp, 0, 0);
-
-		  hsp->active = 0;
-		  break;
-	}
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
-	if (open_hscxstate(st->l1.hardware, hs->hscx))
-		return (-1);
-
-	st->l1.hscx = hs->hscx;
-	st->l2.l2l1 = hscx_l2l1;
-	st->ma.manl1 = hscx_manl1;
-	st->l2.l2l1discardq = hscx_l2l1discardq;
-
-	st->l1.sbufpool = &hs->sbufpool;
-	st->l1.rbufpool = &hs->rbufpool;
-	st->l1.smallpool = &hs->smallpool;
-	st->l1.act_state = 0;
-	st->l1.requestpull = 0;
-
-	hs->st = st;
-	return (0);
-}
-
-void
-teles_reportcard(int cardnr)
-{
-	printk(KERN_DEBUG "teles_reportcard\n");
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/config.c linux/drivers/isdn/teles/config.c
--- v2.1.36/linux/drivers/isdn/teles/config.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/config.c	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $
- *
- * $Log: config.c,v $
- * Revision 1.1  1996/04/13 10:23:11  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include "teles.h"
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- * 
- * { membase,irq,portbase,protocol,NULL }
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
- *
- * Cards which don't have an io port (Teles 8 bit cards for
- * example) can be entered with io port 0x0
- *
- * For the Teles 16.3, membase has to be set to 0.
- *
- */
-
-struct IsdnCard cards[] =
-{
-	{(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL},	/* example */
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-};
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/fsm.c linux/drivers/isdn/teles/fsm.c
--- v2.1.36/linux/drivers/isdn/teles/fsm.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/fsm.c	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/* $Id: fsm.c,v 1.3 1997/02/16 01:04:12 fritz Exp $
- *
- * $Log: fsm.c,v $
- * Revision 1.3  1997/02/16 01:04:12  fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
- *
- * Revision 1.2  1996/04/29 22:49:57  fritz
- * Removed compatibility-macros.
- *
- * Revision 1.1  1996/04/13 10:23:41  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-void
-FsmNew(struct Fsm *fsm,
-       struct FsmNode *fnlist, int fncount)
-{
-	int             i;
-
-	fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
-					  GFP_KERNEL, "Fsm jumpmatrix");
-	memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
-	for (i = 0; i < fncount; i++)
-		fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
-			      fnlist[i].state] = (int) fnlist[i].routine;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
-	Sfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
-	void            (*r) (struct FsmInst *, int, void *);
-	char            str[80];
-
-	r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
-	if (r) {
-		if (fi->debug) {
-			sprintf(str, "State %s Event %s",
-				fi->fsm->strState[fi->state],
-				fi->fsm->strEvent[event]);
-			fi->printdebug(fi, str);
-		}
-		r(fi, event, arg);
-		return (0);
-	} else {
-		if (fi->debug) {
-			sprintf(str, "State %s Event %s no routine",
-				fi->fsm->strState[fi->state],
-				fi->fsm->strEvent[event]);
-			fi->printdebug(fi, str);
-		}
-		return (!0);
-	}
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
-	char            str[80];
-
-	fi->state = newstate;
-	if (fi->debug) {
-		sprintf(str, "ChangeState %s",
-			fi->fsm->strState[newstate]);
-		fi->printdebug(fi, str);
-	}
-}
-
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
-	FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
-	ft->fi = fi;
-	ft->tl.function = (void *) FsmExpireTimer;
-	ft->tl.data = (long) ft;
-	init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if 0
-	if (ft->fi->debug) {
-		sprintf(str, "FsmDelTimer %lx %d", ft, where);
-		ft->fi->printdebug(ft->fi, str);
-	}
-#endif
-
-	del_timer(&ft->tl);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
-	    int millisec, int event, void *arg, int where)
-{
-
-#if 0
-	if (ft->fi->debug) {
-		sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
-		ft->fi->printdebug(ft->fi, str);
-	}
-#endif
-
-	if (ft->tl.next || ft->tl.prev) {
-		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
-		return -1;
-	}
-	init_timer(&ft->tl);
-	ft->event = event;
-	ft->arg = arg;
-	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
-	add_timer(&ft->tl);
-	return 0;
-}
-
-int
-FsmTimerRunning(struct FsmTimer *ft)
-{
-	return (ft->tl.next != NULL);
-}
-
-void
-jiftime(char *s, long mark)
-{
-	s += 8;
-
-	*s-- = '\0';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = '.';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 6 + '0';
-	mark /= 6;
-	*s-- = ':';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 10 + '0';
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/isdnl2.c linux/drivers/isdn/teles/isdnl2.c
--- v2.1.36/linux/drivers/isdn/teles/isdnl2.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/isdnl2.c	Wed Dec 31 16:00:00 1969
@@ -1,1320 +0,0 @@
-/* $Id: isdnl2.c,v 1.3 1996/11/23 11:32:57 keil Exp $
- *
- * $Log: isdnl2.c,v $
- * Revision 1.3  1996/11/23 11:32:57  keil
- * X.75 bugfixies; Thanks to Martin Maurer
- *
- * Revision 1.2  1996/05/17 03:46:15  fritz
- * General cleanup.
- *
- * Revision 1.1  1996/04/13 10:24:16  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-#define TIMER_1 2000
-
-static void     l2m_debug(struct FsmInst *fi, char *s);
-
-struct Fsm      l2fsm =
-{NULL, 0, 0};
-
-enum {
-	ST_L2_1,
-	ST_L2_3,
-	ST_L2_4,
-	ST_L2_5,
-	ST_L2_6,
-	ST_L2_7,
-	ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8+1)
-
-static char    *strL2State[] =
-{
-	"ST_L2_1",
-	"ST_L2_3",
-	"ST_L2_4",
-	"ST_L2_5",
-	"ST_L2_6",
-	"ST_L2_7",
-	"ST_L2_8",
-};
-
-enum {
-	EV_L2_UI,
-	EV_L2_SABMX,
-	EV_L2_UA,
-	EV_L2_DISC,
-	EV_L2_I,
-	EV_L2_RR,
-	EV_L2_REJ,
-	EV_L2_FRMR,
-	EV_L2_DL_DATA,
-	EV_L2_DL_ESTABLISH,
-	EV_L2_MDL_ASSIGN,
-	EV_L2_DL_UNIT_DATA,
-	EV_L2_DL_RELEASE,
-	EV_L2_MDL_NOTEIPROC,
-	EV_L2_T200,
-	EV_L2_ACK_PULL,
-	EV_L2_T203,
-	EV_L2_RNR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
-
-static char    *strL2Event[] =
-{
-	"EV_L2_UI",
-	"EV_L2_SABMX",
-	"EV_L2_UA",
-	"EV_L2_DISC",
-	"EV_L2_I",
-	"EV_L2_RR",
-	"EV_L2_REJ",
-	"EV_L2_FRMR",
-	"EV_L2_DL_DATA",
-	"EV_L2_DL_ESTABLISH",
-	"EV_L2_MDL_ASSIGN",
-	"EV_L2_DL_UNIT_DATA",
-	"EV_L2_DL_RELEASE",
-	"EV_L2_MDL_NOTEIPROC",
-	"EV_L2_T200",
-	"EV_L2_ACK_PULL",
-	"EV_L2_T203",
-	"EV_L2_RNR",
-};
-
-int             errcount = 0;
-
-static int      l2addrsize(struct Layer2 *tsp);
-
-static int
-cansend(struct PStack *st)
-{
-	int             p1;
-
-	p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
-	return (st->l2.vs != p1);
-}
-
-static void
-discard_i_queue(struct PStack *st)
-{
-	struct BufHeader *ibh;
-
-	while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
-		BufPoolRelease(ibh);
-}
-
-int
-l2headersize(struct Layer2 *tsp, int UI)
-{
-	return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
-}
-
-int
-l2addrsize(struct Layer2 *tsp)
-{
-	return (tsp->laptype == LAPD ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *tsp,
-	   struct BufHeader *ibh, int rsp)
-{
-	byte           *ptr = DATAPTR(ibh);
-	int             crbit;
-
-	if (tsp->laptype == LAPD) {
-		crbit = rsp;
-		if (!tsp->orig)
-			crbit = !crbit;
-		*ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
-		*ptr++ = (tsp->tei << 1) | 1;
-		return (2);
-	} else {
-		crbit = rsp;
-		if (tsp->orig)
-			crbit = !crbit;
-		if (crbit)
-			*ptr++ = 1;
-		else
-			*ptr++ = 3;
-		return (1);
-	}
-}
-
-static void
-enqueue_ui(struct PStack *st,
-	   struct BufHeader *ibh)
-{
-	st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static void
-enqueue_super(struct PStack *st,
-	      struct BufHeader *ibh)
-{
-	st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static int
-legalnr(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-	int             lnr, lvs;
-
-	lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
-	lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
-	return (lnr <= lvs);
-}
-
-static void
-setva(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-
-	if (l2->va != nr) {
-                while (l2->va != nr) {
-                        l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
-                        BufPoolRelease(l2->windowar[l2->sow]);
-                        l2->sow = (l2->sow + 1) % l2->window;
-                }
-                if (st->l4.l2writewakeup)
-                        st->l4.l2writewakeup(st);
-        }
-}
-
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
-	FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2s2(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-
-	byte           *ptr;
-	int             i;
-
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x3;
-
-	enqueue_ui(st, ibh);
-}
-
-static void
-l2s3(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-
-	st->l2.l2l3(st, DL_UNIT_DATA, ibh);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh;
-	int             i;
-	byte           *ptr;
-
-	FsmChangeState(fi, ST_L2_5);
-	st->l2.rc = 0;
-
-	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 1");
-
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-		return;
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	if (st->l2.extended)
-		*ptr = 0x7f;
-	else
-		*ptr = 0x3f;
-	ibh->datasize = i + 1;
-
-	enqueue_super(st, ibh);
-}
-
-static void
-l2s11(struct FsmInst *fi, int event, void *arg)
-{
-	establishlink(fi);
-}
-
-static void
-l2s13(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	byte           *ptr;
-	struct BufHeader *ibh;
-	int             i;
-
-	FsmChangeState(fi, ST_L2_6);
-
-	FsmDelTimer(&st->l2.t203_timer, 1);
-	if (st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t200_timer, 2);
-		st->l2.t200_running = 0;
-	}
-	st->l2.rc = 0;
-	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 2");
-
-
-	if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
-		goto nodisc;
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
-		return;
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x53;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-      nodisc:
-	discard_i_queue(st);
-}
-
-static void
-l2s12(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	int             i;
-
-	BufPoolRelease(ibh);
-	st->l2.vs = 0;
-	st->l2.va = 0;
-	st->l2.vr = 0;
-	st->l2.sow = 0;
-	FsmChangeState(fi, ST_L2_7);
-	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 3");
-
-	st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
-		return;
-	i = sethdraddr(&(st->l2), ibh, !0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x73;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-}
-
-static void
-l2s14(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	struct Channel *chanp = st->l4.userdata;
-	byte           *ptr;
-	int             i, p;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&(st->l2));
-	p = (*ptr) & 0x10;
-	BufPoolRelease(ibh);
-
-	FsmChangeState(fi, ST_L2_4);
-
-	FsmDelTimer(&st->l2.t203_timer, 3);
-	if (st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t200_timer, 4);
-		st->l2.t200_running = 0;
-	}
-	if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
-		goto noresponse;
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
-		return;
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x63 | (p ? 0x10 : 0x0);
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-      noresponse:
-	st->l2.l2man(st, DL_RELEASE, NULL);
-
-}
-
-static void
-l2s5(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             f;
-	byte           *data;
-
-	data = DATAPTR(ibh);
-	data += l2addrsize(&(st->l2));
-
-	f = *data & 0x10;
-	BufPoolRelease(ibh);
-
-	if (f) {
-		st->l2.vs = 0;
-		st->l2.va = 0;
-		st->l2.vr = 0;
-		st->l2.sow = 0;
-		FsmChangeState(fi, ST_L2_7);
-
-		FsmDelTimer(&st->l2.t200_timer, 5);
-		if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 4");
-
-
-		st->l2.l2man(st, DL_ESTABLISH, NULL);
-	}
-}
-
-static void
-l2s15(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             f;
-	byte           *data;
-
-	data = DATAPTR(ibh);
-	data += l2addrsize(&st->l2);
-
-	f = *data & 0x10;
-	BufPoolRelease(ibh);
-
-	if (f) {
-		FsmDelTimer(&st->l2.t200_timer, 6);
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	}
-}
-
-static void
-l2s6(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	struct BufHeader *ibh = arg;
-	int             p, i, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
-		goto noresp;
-
-	if ((!rsp) && p) {
-		if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
-			i = sethdraddr(l2, ibh, !0);
-			ptr = DATAPTR(ibh);
-			ptr += i;
-
-			if (l2->extended) {
-				*ptr++ = 0x1;
-				*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-				i += 2;
-			} else {
-				*ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
-				i += 1;
-			}
-			ibh->datasize = i;
-			enqueue_super(st, ibh);
-		}
-	}
-      noresp:
-	if (legalnr(st, seq))
-		if (seq == st->l2.vs) {
-			setva(st, seq);
-			FsmDelTimer(&st->l2.t200_timer, 7);
-			st->l2.t200_running = 0;
-			FsmDelTimer(&st->l2.t203_timer, 8);
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 5");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		} else if (st->l2.va != seq) {
-			setva(st, seq);
-			FsmDelTimer(&st->l2.t200_timer, 9);
-			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 6");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		}
-}
-
-static void
-l2s7(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             i;
-	byte           *ptr;
-	struct IsdnCardState *sp = st->l1.hardware;
-	char            str[64];
-
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-
-	if (st->l2.laptype == LAPD)
-		if (sp->dlogflag) {
-			sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-			dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-				  str);
-		}
-	BufQueueLink(&st->l2.i_queue, ibh);
-
-	st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-l2s8(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	struct BufHeader *ibh2;
-	struct IsdnCardState *sp = st->l1.hardware;
-	struct Layer2  *l2 = &(st->l2);
-	int             i, p, seq, nr, wasok;
-	char            str[64];
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(l2);
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[0] >> 1;
-		nr = (ptr[1] >> 1) & 0x7f;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 1) & 0x7;
-		nr = (ptr[0] >> 5) & 0x7;
-	}
-
-	if (l2->vr == seq) {
-		wasok = !0;
-
-		l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
-		l2->rejexp = 0;
-
-		ptr = DATAPTR(ibh);
-		if (st->l2.laptype == LAPD)
-			if (sp->dlogflag) {
-				sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
-				dlogframe(st->l1.hardware, ptr + l2->ihsize,
-					ibh->datasize - l2->ihsize, str);
-			}
-	      label8_1:
-		if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
-			goto noRR;
-
-		if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
-			i = sethdraddr(&(st->l2), ibh2, !0);
-			ptr = DATAPTR(ibh2);
-			ptr += i;
-
-			if (l2->extended) {
-				*ptr++ = 0x1;
-				*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-				i += 2;
-			} else {
-				*ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
-				i += 1;
-			}
-			ibh2->datasize = i;
-			enqueue_super(st, ibh2);
-		      noRR:
-		}
-	} else {
-	        /* n(s)!=v(r) */
-		wasok = 0;
-		BufPoolRelease(ibh);
-		if (st->l2.rejexp) {
-			if (p)
-				goto label8_1;
-		} else {
-			st->l2.rejexp = !0;
-			if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
-				i = sethdraddr(&(st->l2), ibh2, p);
-				ptr = DATAPTR(ibh2);
-				ptr += i;
-
-				if (l2->extended) {
-					*ptr++ = 0x9;
-					*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-					i += 2;
-				} else {
-					*ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
-					i += 1;
-				}
-				ibh2->datasize = i;
-				enqueue_super(st, ibh2);
-			}
-		}
-	}
-
-	if (legalnr(st, nr))
-		if (nr == st->l2.vs) {
-			setva(st, nr);
-			FsmDelTimer(&st->l2.t200_timer, 10);
-			st->l2.t200_running = 0;
-			FsmDelTimer(&st->l2.t203_timer, 11);
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 5");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		} else if (nr != st->l2.va) {
-			setva(st, nr);
-			FsmDelTimer(&st->l2.t200_timer, 12);
-			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 6");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		}
-	if (wasok)
-		st->l2.l2l3(st, DL_DATA, ibh);
-
-}
-
-static void
-l2s17(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.tei = (int) arg;
-	establishlink(fi);
-}
-
-static void
-enquiry_response(struct PStack *st)
-{
-	struct BufHeader *ibh2;
-	int             i;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
-		i = sethdraddr(&(st->l2), ibh2, !0);
-		ptr = DATAPTR(ibh2);
-		ptr += i;
-
-		if (l2->extended) {
-			*ptr++ = 0x1;
-			*ptr++ = (l2->vr << 1) | 0x1;
-			i += 2;
-		} else {
-			*ptr++ = (l2->vr << 5) | 0x1 | 0x10;
-			i += 1;
-		}
-		ibh2->datasize = i;
-		enqueue_super(st, ibh2);
-	}
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-	int             p1;
-
-	if (l2->vs != nr) {
-		while (l2->vs != nr) {
-
-			l2->vs = l2->vs - 1;
-			if (l2->vs < 0)
-				l2->vs += l2->extended ? 128 : 8;
-
-			p1 = l2->vs - l2->va;
-			if (p1 < 0)
-				p1 += l2->extended ? 128 : 8;
-			p1 = (p1 + l2->sow) % l2->window;
-
-			BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
-		}
-		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-	}
-}
-
-static void
-l2s16(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             p, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &(st->l2);
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if ((!rsp) && p)
-		enquiry_response(st);
-
-	if (!legalnr(st, seq))
-		return;
-
-	setva(st, seq);
-	invoke_retransmission(st, seq);
-
-}
-
-static void
-l2s19(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2s20(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	int             i;
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (st->l2.rc == st->l2.n200) {
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	} else {
-		st->l2.rc++;
-
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 7");
-
-		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-			return;
-
-		i = sethdraddr(&st->l2, ibh, 0);
-		ptr = DATAPTR(ibh);
-		ptr += i;
-		if (st->l2.extended)
-			*ptr = 0x7f;
-		else
-			*ptr = 0x3f;
-		ibh->datasize = i + 1;
-		enqueue_super(st, ibh);
-	}
-}
-
-static void
-l2s21(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	int             i;
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (st->l2.rc == st->l2.n200) {
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	} else {
-		st->l2.rc++;
-
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 8");
-
-
-		if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
-			goto nodisc;
-
-		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-			return;
-
-		i = sethdraddr(&st->l2, ibh, 0);
-		ptr = DATAPTR(ibh);
-		ptr += i;
-		*ptr = 0x53;
-		ibh->datasize = i + 1;
-		enqueue_super(st, ibh);
-	      nodisc:
-
-	}
-}
-
-static void
-l2s22(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh;
-	struct Layer2  *l2 = &st->l2;
-	byte           *ptr;
-	int             p1;
-
-	if (!cansend(st))
-		return;
-
-	if (BufQueueUnlink(&ibh, &l2->i_queue))
-		return;
-
-
-	p1 = l2->vs - l2->va;
-	if (p1 < 0)
-		p1 += l2->extended ? 128 : 8;
-	p1 = (p1 + l2->sow) % l2->window;
-	l2->windowar[p1] = ibh;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		*ptr++ = l2->vs << 1;
-		*ptr++ = (l2->vr << 1) | 0x1;
-		l2->vs = (l2->vs + 1) % 128;
-	} else {
-		*ptr++ = (l2->vr << 5) | (l2->vs << 1);
-		l2->vs = (l2->vs + 1) % 8;
-	}
-
-	st->l2.l2l1(st, PH_DATA_PULLED, ibh);
-
-	if (!st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t203_timer, 13);
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 9");
-
-		st->l2.t200_running = !0;
-	}
-	if (l2->i_queue.head && cansend(st))
-		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
-		ptr = DATAPTR(ibh);
-		ptr += sethdraddr(&st->l2, ibh, 0);
-
-		if (st->l2.extended) {
-			*ptr++ = 0x1;
-			*ptr++ = (st->l2.vr << 1) | 1;
-		} else {
-			*ptr++ = (st->l2.vr << 5) | 0x11;
-		}
-		ibh->datasize = ptr - DATAPTR(ibh);
-		enqueue_super(st, ibh);
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 10");
-
-		st->l2.t200_running = !0;
-	}
-}
-
-static void
-l2s23(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.t200_running = 0;
-
-	st->l2.rc = 1;
-	FsmChangeState(fi, ST_L2_8);
-	transmit_enquiry(st);
-}
-
-static void
-l2s24(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             p, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if (rsp && p) {
-		if (legalnr(st, seq)) {
-			FsmChangeState(fi, ST_L2_7);
-			setva(st, seq);
-			if (st->l2.t200_running) {
-				FsmDelTimer(&st->l2.t200_timer, 14);
-				st->l2.t200_running = 0;
-			}
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 11");
-
-			invoke_retransmission(st, seq);
-		}
-	} else {
-		if (!rsp && p)
-			enquiry_response(st);
-		if (legalnr(st, seq)) {
-			setva(st, seq);
-		}
-	}
-}
-
-static void
-l2s25(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.rc = 0;
-	FsmChangeState(fi, ST_L2_8);
-	transmit_enquiry(st);
-}
-
-static void
-l2s26(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	if (st->l2.rc == st->l2.n200) {
-		l2s13(fi, event, NULL);
-	} else {
-		st->l2.rc++;
-		transmit_enquiry(st);
-	}
-}
-
-static void
-l2s27(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	int             i, p, est;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&st->l2);
-
-	if (st->l2.extended)
-		p = ptr[1] & 0x1;
-	else
-		p = ptr[0] & 0x10;
-
-	BufPoolRelease(ibh);
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
-		return;
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x63 | p;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-	if (st->l2.vs != st->l2.va) {
-		discard_i_queue(st);
-		est = !0;
-	} else
-		est = 0;
-
-	FsmDelTimer(&st->l2.t200_timer, 15);
-	st->l2.t200_running = 0;
-
-	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 12");
-
-	st->l2.vs = 0;
-	st->l2.va = 0;
-	st->l2.vr = 0;
-	st->l2.sow = 0;
-
-
-	if (est)
-		st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-}
-
-static void
-l2s28(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	char            tmp[64];
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&st->l2);
-	ptr++;
-
-	if (st->l2.l2m.debug) {
-		if (st->l2.extended)
-			sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
-				ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
-		else
-			sprintf(tmp, "FRMR information %2x %2x %2x",
-				ptr[0], ptr[1], ptr[2]);
-
-		l2m_debug(&st->l2.l2m, tmp);
-	}
-	BufPoolRelease(ibh);
-}
-
-static int
-IsUI(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x3);
-}
-
-static int
-IsUA(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x63);
-}
-
-static int
-IsDISC(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x43);
-}
-
-static int
-IsRR(byte * data, int ext)
-{
-	if (ext)
-		return (data[0] == 0x1);
-	else
-		return ((data[0] & 0xf) == 1);
-}
-
-static int
-IsI(byte * data, int ext)
-{
-	return ((data[0] & 0x1) == 0x0);
-}
-
-static int
-IsSABMX(byte * data, int ext)
-{
-	return (ext ? data[0] == 0x7f : data[0] == 0x3f);
-}
-
-static int
-IsREJ(byte * data, int ext)
-{
-	return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9);
-}
-
-static int
-IsFRMR(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x87);
-}
-
-static int
-IsRNR(byte * data, int ext)
-{
-	if (ext)
-		return (data[0] == 0x5);
-	else
-		return ((data[0] & 0xf) == 5);
-}
-
-static struct FsmNode L2FnList[] =
-{
-	{ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
-	{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
-	{ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
-	{ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
-	{ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
-	{ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
-	{ST_L2_7, EV_L2_DL_DATA, l2s7},
-	{ST_L2_7, EV_L2_DL_RELEASE, l2s13},
-	{ST_L2_7, EV_L2_ACK_PULL, l2s22},
-	{ST_L2_8, EV_L2_DL_RELEASE, l2s13},
-
-	{ST_L2_1, EV_L2_UI, l2s3},
-	{ST_L2_4, EV_L2_UI, l2s3},
-	{ST_L2_4, EV_L2_SABMX, l2s12},
-	{ST_L2_5, EV_L2_UA, l2s5},
-	{ST_L2_6, EV_L2_UA, l2s15},
-	{ST_L2_7, EV_L2_UI, l2s3},
-	{ST_L2_7, EV_L2_DISC, l2s14},
-	{ST_L2_7, EV_L2_I, l2s8},
-	{ST_L2_7, EV_L2_RR, l2s6},
-	{ST_L2_7, EV_L2_REJ, l2s16},
-	{ST_L2_7, EV_L2_SABMX, l2s27},
-	{ST_L2_7, EV_L2_FRMR, l2s28},
-	{ST_L2_8, EV_L2_RR, l2s24},
-	{ST_L2_8, EV_L2_DISC, l2s14},
-	{ST_L2_8, EV_L2_FRMR, l2s28},
-
-	{ST_L2_5, EV_L2_T200, l2s20},
-	{ST_L2_6, EV_L2_T200, l2s21},
-	{ST_L2_7, EV_L2_T200, l2s23},
-	{ST_L2_7, EV_L2_T203, l2s25},
-	{ST_L2_8, EV_L2_T200, l2s26},
-};
-
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
-{
-	struct BufHeader *ibh;
-	byte           *datap;
-	int             ret = !0;
-
-	switch (pr) {
-	  case (PH_DATA):
-
-		  ibh = arg;
-		  datap = DATAPTR(ibh);
-		  datap += l2addrsize(&st->l2);
-
-		  if (IsI(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
-		  else if (IsRR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
-		  else if (IsUI(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
-		  else if (IsSABMX(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
-		  else if (IsUA(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
-		  else if (IsDISC(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
-		  else if (IsREJ(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
-		  else if (IsFRMR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
-		  else if (IsRNR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
-
-		  if (ret)
-			  BufPoolRelease(ibh);
-
-		  break;
-	  case (PH_PULL_ACK):
-		  FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
-		  break;
-	}
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr,
-	    void *arg)
-{
-	switch (pr) {
-	  case (DL_DATA):
-		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
-			  BufPoolRelease((struct BufHeader *) arg);
-		  break;
-	  case (DL_UNIT_DATA):
-		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
-			  BufPoolRelease((struct BufHeader *) arg);
-		  break;
-	}
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr,
-	     void *arg)
-{
-	switch (pr) {
-	  case (DL_ESTABLISH):
-		  FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
-		  break;
-	  case (DL_RELEASE):
-		  FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
-		  break;
-	  case (MDL_NOTEIPROC):
-		  FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
-		  break;
-	}
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr,
-	     void *arg)
-{
-	switch (pr) {
-	  case (MDL_ASSIGN):
-		  FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
-		  break;
-	}
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
-	FsmDelTimer(&st->l2.t200_timer, 15);
-	FsmDelTimer(&st->l2.t203_timer, 16);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *s)
-{
-	struct PStack  *st = fi->userdata;
-	char            tm[32], str[256];
-
-	jiftime(tm, jiffies);
-	sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
-	teles_putstatus(str);
-}
-
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
-	st->l1.l1l2 = isdnl2_l1l2;
-	st->l3.l3l2 = isdnl2_l3l2;
-	st->ma.manl2 = isdnl2_manl2;
-	st->ma.teil2 = isdnl2_teil2;
-
-	st->l2.uihsize = l2headersize(&st->l2, !0);
-	st->l2.ihsize = l2headersize(&st->l2, 0);
-	BufQueueInit(&(st->l2.i_queue));
-	st->l2.rejexp = 0;
-	st->l2.debug = 1;
-
-	st->l2.l2m.fsm = &l2fsm;
-	st->l2.l2m.state = ST_L2_1;
-	st->l2.l2m.debug = 0;
-	st->l2.l2m.userdata = st;
-	st->l2.l2m.printdebug = l2m_debug;
-	strcpy(st->l2.debug_id, debug_id);
-
-	FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
-	FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
-	st->l2.t200_running = 0;
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-void
-Isdnl2New(void)
-{
-	l2fsm.state_count = L2_STATE_COUNT;
-	l2fsm.event_count = L2_EVENT_COUNT;
-	l2fsm.strEvent = strL2Event;
-	l2fsm.strState = strL2State;
-	FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
-}
-
-void
-Isdnl2Free(void)
-{
-	FsmFree(&l2fsm);
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c
--- v2.1.36/linux/drivers/isdn/teles/isdnl3.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/isdnl3.c	Wed Dec 31 16:00:00 1969
@@ -1,673 +0,0 @@
-/* $Id: isdnl3.c,v 1.13 1997/02/16 12:12:51 fritz Exp $
- *
- * $Log: isdnl3.c,v $
- * Revision 1.13  1997/02/16 12:12:51  fritz
- * Bugfix: SI2 was nont initialized on incoming calls.
- *
- * Revision 1.12  1997/02/11 01:39:20  keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.11  1996/09/29 19:41:58  fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.10  1996/09/25 18:32:43  keil
- * response for STATUS_ENQ message added
- *
- * Revision 1.9  1996/06/06 14:22:27  fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.8  1996/06/03 20:35:04  fritz
- * Fixed typos.
- *
- * Revision 1.7  1996/06/03 20:03:39  fritz
- * Fixed typos.
- *
- * Revision 1.6  1996/05/21 11:33:50  keil
- * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message.
- *
- * Revision 1.5  1996/05/18 01:37:16  fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.4  1996/05/17 03:46:16  fritz
- * General cleanup.
- *
- * Revision 1.3  1996/04/30 21:57:53  isdn4dev
- * remove some debugging code, improve callback   Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:45:05  fritz
- * Changed to report all incoming calls to Linklevel, not just those
- * with Service 7.
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:24:45  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#define P_1TR6
-#include "teles.h"
-#include "l3_1TR6.h"
-#define DEBUG_1TR6 0
-
-static void
-i_down(struct PStack *st,
-       struct BufHeader *ibh)
-{
-	st->l3.l3l2(st, DL_DATA, ibh);
-}
-
-static void
-newl3state(struct PStack *st, int state)
-{
-	st->l3.state = state;
-	if (DEBUG_1TR6 > 4)
-		printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n",
-		       st->pa->bchannel, st->pa->callref, state);
-
-}
-
-static void
-l3_message(struct PStack *st, int mt)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	int             size;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = mt;
-	size += 4;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-}
-
-static void
-l3s3(struct PStack *st, byte pr, void *arg)
-{
-	l3_message(st, MT_RELEASE);
-	newl3state(st, 19);
-}
-
-static void
-l3s4(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s4_1(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 19);
-	l3_message(st, MT_RELEASE);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s5(struct PStack *st, byte pr,
-     void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	char           *teln;
-
-	st->l3.callref = st->pa->callref;
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_SETUP;
-	*p++ = 0xa1;
-
-	/*
-         * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
-         */
-	switch (st->pa->setup.si1) {
-	  case 1:		/* Telephony                               */
-		  *p++ = 0x4;	/* BC-IE-code                              */
-		  *p++ = 0x3;	/* Length                                  */
-		  *p++ = 0x90;	/* Coding Std. national, 3.1 kHz audio     */
-		  *p++ = 0x90;	/* Circuit-Mode 64kbps                     */
-		  *p++ = 0xa3;	/* A-Law Audio                             */
-		  break;
-	  case 5:		/* Datatransmission 64k, BTX               */
-	  case 7:		/* Datatransmission 64k                    */
-	  default:
-		  *p++ = 0x4;	/* BC-IE-code                              */
-		  *p++ = 0x2;	/* Length                                  */
-		  *p++ = 0x88;	/* Coding Std. nat., unrestr. dig. Inform. */
-		  *p++ = 0x90;	/* Packet-Mode 64kbps                      */
-		  break;
-	}
-	/*
-	 * What about info2? Mapping to High-Layer-Compatibility?
-	 */
-	if (st->pa->setup.eazmsn[0] != '\0') {
-		*p++ = 0x6c;
-		*p++ = strlen(st->pa->setup.eazmsn) + 1;
-		/* Classify as AnyPref. */
-		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-		teln = st->pa->setup.eazmsn;
-		while (*teln)
-			*p++ = *teln++ & 0x7f;
-	}
-	*p++ = 0x70;
-	*p++ = strlen(st->pa->setup.phone) + 1;
-	/* Classify as AnyPref. */
-	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
-	teln = st->pa->setup.phone;
-	while (*teln)
-		*p++ = *teln++ & 0x7f;
-
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	newl3state(st, 1);
-	i_down(st, dibh);
-
-}
-
-static void
-l3s6(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			0x18, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_WARNING "octect 3 not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 3);
-	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3s7(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 12);
-	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-static void
-l3s8(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3s11(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 4);
-	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3s12(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int		bcfound = 0;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	p += st->l2.uihsize;
-	st->pa->callref = getcallref(p);
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	/*
-         * Channel Identification
-         */
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x18, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-		bcfound++ ;
-	} else
-		printk(KERN_WARNING "l3s12: Channel ident not found\n");
-
-	p = DATAPTR(ibh);
-	if (st->protocol == ISDN_PTYPE_1TR6) {
-		if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) {
-			st->pa->setup.si1 = p[2];
-			st->pa->setup.si2 = p[3];
-		} else
-			printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n");
-	} else {
-		/*
-                 * Bearer Capabilities
-                 */
-		if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
-			st->pa->setup.si2 = 0;
-			switch (p[2] & 0x1f) {
-			  case 0x00:
-                                  /* Speech */
-			  case 0x10:
-                                  /* 3.1 Khz audio */
-				  st->pa->setup.si1 = 1;
-				  break;
-			  case 0x08:
-                                  /* Unrestricted digital information */
-				  st->pa->setup.si1 = 7;
-				  break;
-			  case 0x09:
-                                  /* Restricted digital information */
-				  st->pa->setup.si1 = 2;
-				  break;
-			  case 0x11:
-                                  /* Unrestr. digital information  with tones/announcements */
-				  st->pa->setup.si1 = 3;
-				  break;
-			  case 0x18:
-                                  /* Video */
-				  st->pa->setup.si1 = 4;
-				  break;
-			  default:
-				  st->pa->setup.si1 = 0;
-			}
-		} else
-			printk(KERN_WARNING "l3s12: Bearer capabilities not found\n");
-	}
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x70, 0)))
-		iecpy(st->pa->setup.eazmsn, p, 1);
-	else
-		strcpy(st->pa->setup.eazmsn, "");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x6c, 0))) {
-		st->pa->setup.plan = p[2];
-		if (st->protocol == ISDN_PTYPE_1TR6) {
-			iecpy(st->pa->setup.phone, p, 1);
-		} else {
-			st->pa->setup.screen = p[3];
-			iecpy(st->pa->setup.phone, p, 2);
-		}
-	} else
-		strcpy(st->pa->setup.phone, "");
-	BufPoolRelease(ibh);
-
-        if (bcfound) {
-                if (st->pa->setup.si1 != 7) {
-                        printk(KERN_DEBUG "non-digital call: %s -> %s\n",
-                               st->pa->setup.phone,
-                               st->pa->setup.eazmsn);
-                }
-                newl3state(st, 6);
-                st->l3.l3l4(st, CC_SETUP_IND, NULL);
-        }
-}
-
-static void
-l3s13(struct PStack *st, byte pr, void *arg)
-{
-	newl3state(st, 0);
-}
-
-static void
-l3s16(struct PStack *st, byte pr,
-      void *arg)
-{
-	st->l3.callref = 0x80 + st->pa->callref;
-	l3_message(st, MT_CONNECT);
-	newl3state(st, 8);
-}
-
-static void
-l3s17(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3s18(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	int             size;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_DISCONNECT;
-	size += 4;
-
-	*p++ = IE_CAUSE;
-	*p++ = 0x2;
-	*p++ = 0x80;
-	*p++ = 0x90;
-	size += 4;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-
-	newl3state(st, 11);
-}
-
-static void
-l3s19(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	l3_message(st, MT_RELEASE_COMPLETE);
-	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-}
-
-static void
-l3s20(struct PStack *st, byte pr,
-      void *arg)
-{
-	l3_message(st, MT_ALERTING);
-	newl3state(st, 7);
-}
-
-static void
-l3s21(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh=arg;
-	byte           *p;
-	int             size;
-
-	BufPoolRelease(dibh);
-	
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_STATUS;
-	size += 4;
-
-	*p++ = IE_CAUSE;
-	*p++ = 0x2;
-	*p++ = 0x80;
-	*p++ = 0x9E; /* answer status enquire */
-	size += 4;
-
-	*p++ = 0x14; /* CallState */
-	*p++ = 0x1;
-	*p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
-	size += 3;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-
-}
-
-struct stateentry {
-	int             state;
-	byte            primitive;
-	void            (*rout) (struct PStack *, byte, void *);
-};
-
-static struct stateentry downstatelist[] =
-{
-        {0,CC_SETUP_REQ,l3s5},
-        {1,CC_DISCONNECT_REQ,l3s18},
-        {1,CC_RELEASE_REQ,l3s3},
-        {1,CC_DLRL,l3s13},
-        {3,CC_DISCONNECT_REQ,l3s18},
-        {3,CC_RELEASE_REQ,l3s3},
-        {3,CC_DLRL,l3s13},
-        {4,CC_RELEASE_REQ,l3s3},
-        {4,CC_DISCONNECT_REQ,l3s18},
-        {4,CC_DLRL,l3s13},
-        {6,CC_RELEASE_REQ,l3s3},
-        {6,CC_DISCONNECT_REQ,l3s18},
-        {6,CC_ALERTING_REQ,l3s20},
-        {6,CC_DLRL,l3s13},
-        {7,CC_RELEASE_REQ,l3s3},
-        {7,CC_SETUP_RSP,l3s16},
-        {7,CC_DLRL,l3s13},
-        {8,CC_RELEASE_REQ,l3s3},
-        {8,CC_DISCONNECT_REQ,l3s18},
-        {8,CC_DLRL,l3s13},
-        {10,CC_DISCONNECT_REQ,l3s18},
-        {10,CC_RELEASE_REQ,l3s3},
-        {10,CC_DLRL,l3s13},
-        {11,CC_RELEASE_REQ,l3s3},
-        {12,CC_RELEASE_REQ,l3s3},
-        {19,CC_DLRL,l3s13},
-};
-
-static int      downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist[] =
-{
-        {0,MT_STATUS_ENQUIRY,l3s21},
-        {0,MT_SETUP,l3s12},
-        {1,MT_STATUS_ENQUIRY,l3s21},
-        {1,MT_CALL_PROCEEDING,l3s6},
-        {1,MT_SETUP_ACKNOWLEDGE,l3s6},
-        {1,MT_RELEASE_COMPLETE,l3s4},
-        {1,MT_RELEASE,l3s19},
-        {1,MT_DISCONNECT,l3s7},
-        {3,MT_STATUS_ENQUIRY,l3s21},
-        {3,MT_DISCONNECT,l3s7},
-        {3,MT_CONNECT,l3s8},
-        {3,MT_ALERTING,l3s11},
-        {3,MT_RELEASE,l3s19},
-        {3,MT_RELEASE_COMPLETE,l3s4},
-        {4,MT_STATUS_ENQUIRY,l3s21},
-        {4,MT_CONNECT,l3s8},
-        {4,MT_DISCONNECT,l3s7},
-        {4,MT_RELEASE,l3s19},
-        {4,MT_RELEASE_COMPLETE,l3s4},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {6,MT_SETUP,l3s12},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {7,MT_RELEASE,l3s19},
-        {7,MT_RELEASE_COMPLETE,l3s4_1},
-        {7,MT_DISCONNECT,l3s7},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {8,MT_RELEASE,l3s19},
-        {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
-        {8,MT_DISCONNECT,l3s7},
-        {8,MT_RELEASE_COMPLETE,l3s4_1},
-        {10,MT_STATUS_ENQUIRY,l3s21},
-        {10,MT_DISCONNECT,l3s7},
-        {10,MT_RELEASE,l3s19},
-        {10,MT_RELEASE_COMPLETE,l3s4_1},
-        {11,MT_STATUS_ENQUIRY,l3s21},
-        {11,MT_RELEASE,l3s19},
-        {11,MT_RELEASE_COMPLETE,l3s4},
-        {19,MT_STATUS_ENQUIRY,l3s21},
-        {19,MT_RELEASE_COMPLETE,l3s4},
-};
-
-static int      datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
-
-#ifdef P_1TR6
-#include "l3_1TR6.c"
-#endif
-
-static void
-l3up(struct PStack *st,
-     int pr, void *arg)
-{
-	int             i, mt, size;
-	byte           *ptr;
-	struct BufHeader *ibh = arg;
-
-	if (pr == DL_DATA) {
-		ptr = DATAPTR(ibh);
-		ptr += st->l2.ihsize;
-		size = ibh->datasize - st->l2.ihsize;
-		mt = ptr[3];
-		switch (ptr[0]) {
-#ifdef P_1TR6
-		  case PROTO_DIS_N0:
-			  BufPoolRelease(ibh);
-			  break;
-		  case PROTO_DIS_N1:
-			  for (i = 0; i < datasl_1tr6t_len; i++)
-				  if ((st->l3.state == datastatelist_1tr6t[i].state) &&
-				      (mt == datastatelist_1tr6t[i].primitive))
-					  break;
-			  if (i == datasl_1tr6t_len) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
-						 st->l3.state, mt);
-			  } else
-				  datastatelist_1tr6t[i].rout(st, pr, ibh);
-			  break;
-#endif
-		  case PROTO_EURO:	/* E-DSS1 */
-			  for (i = 0; i < datasllen; i++)
-				  if ((st->l3.state == datastatelist[i].state) &&
-				      (mt == datastatelist[i].primitive))
-					  break;
-			  if (i == datasllen) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
-				 		st->l3.state, mt);
-			  } else
-				  datastatelist[i].rout(st, pr, ibh);
-			  break;
-		  default:
-		          BufPoolRelease(ibh);
-			  break;
-		}
-	} else if (pr == DL_UNIT_DATA) {
-		ptr = DATAPTR(ibh);
-		ptr += st->l2.uihsize;
-		size = ibh->datasize - st->l2.uihsize;
-		mt = ptr[3];
-		switch (ptr[0]) {
-#ifdef P_1TR6
-		  case PROTO_DIS_N0:
-			  BufPoolRelease(ibh);
-			  break;
-		  case PROTO_DIS_N1:
-			  for (i = 0; i < datasl_1tr6t_len; i++)
-				  if ((st->l3.state == datastatelist_1tr6t[i].state) &&
-				      (mt == datastatelist_1tr6t[i].primitive))
-					  break;
-			  if (i == datasl_1tr6t_len) {
-				  if (DEBUG_1TR6 > 0) {
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
-						 ,st->l3.state, mt);
-				  }
-				  BufPoolRelease(ibh);
-			  } else
-				  datastatelist_1tr6t[i].rout(st, pr, ibh);
-			  break;
-#endif
-		  case PROTO_EURO:	/* E-DSS1 */
-			  for (i = 0; i < datasllen; i++)
-				  if ((st->l3.state == datastatelist[i].state) &&
-				      (mt == datastatelist[i].primitive))
-					  break;
-			  if (i == datasllen) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
-				 		st->l3.state, mt);
-			  } else
-				  datastatelist[i].rout(st, pr, ibh);
-			  break;
-		  default:
-		          BufPoolRelease(ibh);
-			  break;
-		}
-	}
-}
-
-static void
-l3down(struct PStack *st,
-       int pr, void *arg)
-{
-	int             i;
-	struct BufHeader *ibh = arg;
-
-	switch (st->protocol) {
-#ifdef P_1TR6
-	  case ISDN_PTYPE_1TR6:
-		  for (i = 0; i < downsl_1tr6t_len; i++)
-			  if ((st->l3.state == downstatelist_1tr6t[i].state) &&
-			      (pr == downstatelist_1tr6t[i].primitive))
-				  break;
-		  if (i == downsl_1tr6t_len) {
-			  if (DEBUG_1TR6 > 0) {
-				  printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr);
-			  }
-		  } else
-			  downstatelist_1tr6t[i].rout(st, pr, ibh);
-		  break;
-#endif
-	  default:
-		  for (i = 0; i < downsllen; i++)
-			  if ((st->l3.state == downstatelist[i].state) &&
-			      (pr == downstatelist[i].primitive))
-				  break;
-		  if (i == downsllen) {
-			  if (DEBUG_1TR6 > 0) {
-				  printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr);
-			  }
-		  } else
-			  downstatelist[i].rout(st, pr, ibh);
-	}
-}
-
-void
-setstack_isdnl3(struct PStack *st)
-{
-	st->l4.l4l3 = l3down;
-	st->l2.l2l3 = l3up;
-	st->l3.state = 0;
-	st->l3.callref = 0;
-	st->l3.debug = 0;
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c
--- v2.1.36/linux/drivers/isdn/teles/l3_1TR6.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/l3_1TR6.c	Wed Dec 31 16:00:00 1969
@@ -1,538 +0,0 @@
-/* $Id: l3_1TR6.c,v 1.7 1997/02/11 01:38:55 keil Exp $
- *
- * $Log: l3_1TR6.c,v $
- * Revision 1.7  1997/02/11 01:38:55  keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.6  1996/09/25 18:34:57  keil
- * missing states in 1TR6 Statemachine added
- *
- * Revision 1.5  1996/09/23 01:53:51  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.4  1996/06/06 14:22:28  fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.3  1996/04/30 21:54:42  isdn4dev
- * SPV, callback , remove some debugging code  Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:47:23  fritz
- * Changed statemachine to allow reject of an incoming call.
- * Report all incoming calls, not just those with Service = 7.
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:25:16  fritz
- * Initial revision
- *
- *
- */
-
-#include	"proto.h"
-
-static void
-l3_1TR6_message(struct PStack *st, int mt, int pd)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = pd;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = mt;
-
-	dibh->datasize = p - DATAPTR(dibh);
-	i_down(st, dibh);
-}
-
-static void
-l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	char           *teln;
-
-	st->l3.callref = st->pa->callref;
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_SETUP;
-
-	if ('S' == (st->pa->setup.phone[0] & 0x5f)) {	/* SPV ??? */
-		/* NSF SPV */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_SPV;	/* SPV */
-		*p++ = st->pa->setup.si1; /* 0 for all Services */
-		*p++ = st->pa->setup.si2; /* 0 for all Services */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_Activate;	/* aktiviere SPV (default) */
-		*p++ = st->pa->setup.si1; /* 0 for all Services */
-		*p++ = st->pa->setup.si2; /* 0 for all Services */
-	}
-	if (st->pa->setup.eazmsn[0]) {
-		*p++ = WE0_origAddr;
-		*p++ = strlen(st->pa->setup.eazmsn) + 1;
-		/* Classify as AnyPref. */
-		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-		teln = st->pa->setup.eazmsn;
-		while (*teln)
-			*p++ = *teln++ & 0x7f;
-	}
-	*p++ = WE0_destAddr;
-	teln = st->pa->setup.phone;
-	if ('S' != (st->pa->setup.phone[0] & 0x5f)) {	/* Keine SPV ??? */
-		*p++ = strlen(st->pa->setup.phone) + 1;
-		st->pa->spv = 0;
-	} else {		/* SPV */
-		*p++ = strlen(st->pa->setup.phone);
-		teln++;		/* skip S */
-		st->pa->spv = 1;
-	}
-	/* Classify as AnyPref. */
-	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-	while (*teln)
-		*p++ = *teln++ & 0x7f;
-
-	*p++ = WE_Shift_F6;
-	/* Codesatz 6 fuer Service */
-	*p++ = WE6_serviceInd;
-	*p++ = 2;		/* len=2 info,info2 */
-	*p++ = st->pa->setup.si1;
-	*p++ = st->pa->setup.si2;
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	newl3state(st, 1);
-	i_down(st, dibh);
-
-}
-
-static void
-l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	p += st->l2.uihsize;
-	st->pa->callref = getcallref(p);
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	/* Channel Identification */
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "l3tu_setup: Channel ident not found\n");
-
-	p = DATAPTR(ibh);
-
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
-		st->pa->setup.si1 = p[2];
-		st->pa->setup.si2 = p[3];
-	} else
-		printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_destAddr, 0)))
-		iecpy(st->pa->setup.eazmsn, p, 1);
-	else
-		strcpy(st->pa->setup.eazmsn, "");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_origAddr, 0))) {
-		iecpy(st->pa->setup.phone, p, 1);
-	} else
-		strcpy(st->pa->setup.phone, "");
-
-	p = DATAPTR(ibh);
-	st->pa->spv = 0;
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_netSpecFac, 0))) {
-		if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
-			st->pa->spv = 1;
-	}
-	BufPoolRelease(ibh);
-
-        /* Signal all services, linklevel takes care of Service-Indicator */
-	if (st->pa->setup.si1 != 7) {
-                printk(KERN_DEBUG "non-digital call: %s -> %s\n",
-                       st->pa->setup.phone,
-                       st->pa->setup.eazmsn);
-	}
-        newl3state(st, 6);
-        st->l3.l3l4(st, CC_SETUP_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "octect 3 not found\n");
-
-
-	BufPoolRelease(ibh);
-	newl3state(st, 2);
-}
-
-static void
-l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "octect 3 not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 3);
-	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_statusCalled, 6))) {
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "status called %x\n", p[2]);
-	} else if (DEBUG_1TR6 > 0)
-		printk(KERN_INFO "statusCalled not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 4);
-	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int             i,tmpcharge=0;
-	char            a_charge[8];
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_chargingInfo, 6))) {
-		iecpy(a_charge, p, 1);
-                for (i = 0; i < strlen (a_charge); i++) {
-     	                tmpcharge *= 10;
-     	                tmpcharge += a_charge[i] & 0xf;
-     	        }
-                if (tmpcharge > st->pa->chargeinfo) {
-     	                st->pa->chargeinfo = tmpcharge;
-     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
-     	        }
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
-	} else if (DEBUG_1TR6 > 2)
-		printk(KERN_INFO "chargingInfo not found\n");
-
-	BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int             i;
-	struct BufHeader *ibh = arg;
-
-	if (DEBUG_1TR6 > 4) {
-		p = DATAPTR(ibh);
-		for (i = 0; i < ibh->datasize; i++) {
-			printk(KERN_INFO "Info DATA %x\n", p[i]);
-		}
-	}
-	BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-        st->pa->chargeinfo=0;
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
-	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-	newl3state(st, 0);
-}
-
-static void
-l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-	byte           *p;
-	int             i,tmpcharge=0;
-	char            a_charge[8];
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_chargingInfo, 6))) {
-		iecpy(a_charge, p, 1);
-                for (i = 0; i < strlen (a_charge); i++) {
-     	                tmpcharge *= 10;
-     	                tmpcharge += a_charge[i] & 0xf;
-     	        }
-                if (tmpcharge > st->pa->chargeinfo) {
-     	                st->pa->chargeinfo = tmpcharge;
-     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
-     	        }
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
-	} else if (DEBUG_1TR6 > 2)
-		printk(KERN_INFO "chargingInfo not found\n");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_cause, 0))) {
-		if (p[1] > 0) {
-			st->pa->cause = p[2];
-		} else {
-			st->pa->cause = 0;
-		}
-		if (DEBUG_1TR6 > 1)
-			printk(KERN_INFO "Cause %x\n", st->pa->cause);
-	} else if (DEBUG_1TR6 > 0)
-		printk(KERN_INFO "Cause not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 12);
-	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-
-static void
-l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->pa->chargeinfo = 0;
-	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3_1tr6_alert(struct PStack *st, byte pr,
-	      void *arg)
-{
-	l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
-	newl3state(st, 7);
-}
-
-static void
-l3_1tr6_conn(struct PStack *st, byte pr,
-	     void *arg)
-{
-	struct BufHeader *dibh;
-	byte *p;
-
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_CONN;
-
-	if (st->pa->spv) {	/* SPV ??? */
-		/* NSF SPV */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_SPV;	/* SPV */
-		*p++ = st->pa->setup.si1;
-		*p++ = st->pa->setup.si2;
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_Activate;	/* aktiviere SPV */
-		*p++ = st->pa->setup.si1;
-		*p++ = st->pa->setup.si2;
-	}
-	dibh->datasize = p - DATAPTR(dibh);
-
-	i_down(st, dibh);
-
-	newl3state(st, 8);
-}
-
-static void
-l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
-{
-	newl3state(st, 0);
-}
-
-static void
-l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte             *p;
-        byte             rejflg;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_DISC;
-
-        if (st->l3.state == 7) {
-                rejflg = 1;
-                *p++ = WE0_cause;       /* Anruf abweisen                */
-                *p++ = 0x01;            /* Laenge = 1                    */
-                *p++ = CAUSE_CallRejected;
-        } else {
-                rejflg = 0;
-                *p++ = WE0_cause;
-                *p++ = 0x0;             /* Laenge = 0 normales Ausloesen */
-        }
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	i_down(st, dibh);
-
-        newl3state(st, 11);
-}
-
-static void
-l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
-{
-	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
-	newl3state(st, 19);
-}
-
-static struct stateentry downstatelist_1tr6t[] =
-{
-	{0, CC_SETUP_REQ, l3_1tr6_setup},
-	{1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{1, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {1, CC_DLRL, l3_1tr6_reset},
-	{2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{2, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {2, CC_DLRL, l3_1tr6_reset},
-	{3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{3, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {3, CC_DLRL, l3_1tr6_reset},
-	{4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{4, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {4, CC_DLRL, l3_1tr6_reset},
-	{6, CC_REJECT_REQ, l3_1tr6_reset},
-	{6, CC_RELEASE_REQ, l3_1tr6_rel_req},
-	{6, CC_SETUP_RSP, l3_1tr6_conn},
-	{6, CC_ALERTING_REQ, l3_1tr6_alert},
-        {6, CC_DLRL, l3_1tr6_reset},
-	{7, CC_SETUP_RSP, l3_1tr6_conn},
-	{7, CC_RELEASE_REQ, l3_1tr6_rel_req},
-	{7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-        {7, CC_DLRL, l3_1tr6_reset},
-	{8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{8, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {8, CC_DLRL, l3_1tr6_reset},
-	{10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{10, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {10, CC_DLRL, l3_1tr6_reset},
-	{12, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {12, CC_DLRL, l3_1tr6_reset},
-        {19, CC_DLRL, l3_1tr6_reset},
-};
-
-static int      downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist_1tr6t[] =
-{
-	{0, MT_N1_SETUP, l3_1tr6_tu_setup},
-	{0, MT_N1_REL, l3_1tr6_tu_rel},
-	{1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
-	{1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
-	{1, MT_N1_REL, l3_1tr6_tu_rel},
-	{1, MT_N1_DISC, l3_1tr6_tu_disc},
-	{2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
-	{2, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{2, MT_N1_CONN, l3_1tr6_tu_connect},
-	{2, MT_N1_REL, l3_1tr6_tu_rel},
-	{2, MT_N1_DISC, l3_1tr6_tu_disc},
-	{2, MT_N1_INFO, l3_1tr6_tu_info_s2},
-	{3, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{3, MT_N1_CONN, l3_1tr6_tu_connect},
-	{3, MT_N1_REL, l3_1tr6_tu_rel},
-	{3, MT_N1_DISC, l3_1tr6_tu_disc},
-	{4, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{4, MT_N1_CONN, l3_1tr6_tu_connect},
-	{4, MT_N1_REL, l3_1tr6_tu_rel},
-	{4, MT_N1_DISC, l3_1tr6_tu_disc},
-	{7, MT_N1_REL, l3_1tr6_tu_rel},
-	{7, MT_N1_DISC, l3_1tr6_tu_disc},
-	{8, MT_N1_REL, l3_1tr6_tu_rel},
-	{8, MT_N1_DISC, l3_1tr6_tu_disc},
-	{8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
-	{10, MT_N1_REL, l3_1tr6_tu_rel},
-	{10, MT_N1_DISC, l3_1tr6_tu_disc},
-	{10, MT_N1_INFO, l3_1tr6_tu_info},
-	{11, MT_N1_REL, l3_1tr6_tu_rel},
-	{12, MT_N1_REL, l3_1tr6_tu_rel},
-	{19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
-};
-
-static int      datasl_1tr6t_len = sizeof(datastatelist_1tr6t) /
-sizeof(struct stateentry);
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h
--- v2.1.36/linux/drivers/isdn/teles/l3_1TR6.h	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/l3_1TR6.h	Wed Dec 31 16:00:00 1969
@@ -1,160 +0,0 @@
-/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
- *
- * $Log: l3_1TR6.h,v $
- * Revision 1.4  1996/09/23 01:53:52  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.3  1996/04/30 21:53:48  isdn4dev
- * Bugs, SPV, Logging in q931.c  Karsten Keil
- *
- * Revision 1.1  1996/04/13 10:25:42  fritz
- * Initial revision
- *
- *
- */
-#ifndef l3_1TR6
-#define l3_1TR6
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE   0x75
-#define MT_N0_CLO_ACK 0x77
-
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-
-
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c
--- v2.1.36/linux/drivers/isdn/teles/llglue.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/llglue.c	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
- *
- * $Log: llglue.c,v $
- * Revision 1.7  1996/10/22 23:14:17  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.6  1996/06/03 20:03:39  fritz
- * Fixed typos.
- *
- * Revision 1.5  1996/05/31 00:58:47  fritz
- * Errata: Reverted change from rev 1.4.
- *
- * Revision 1.4  1996/05/26 14:59:57  fritz
- * Bugfix: maxbufsize had been set without respect to possible X.75 header.
- *
- * Revision 1.3  1996/05/01 14:19:57  fritz
- * Added ISDN_FEATURE_L2_TRANS
- *
- * Revision 1.2  1996/04/29 23:01:46  fritz
- * Added driverId and channel to readstatus().
- *
- * Revision 1.1  1996/04/13 10:26:29  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/malloc.h>
-#include <linux/timer.h>
-
-
-extern struct Channel *chanlist;
-int             drid;
-char            *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-isdn_if         iif;
-
-#define TELES_STATUS_BUFSIZE 4096
-static byte    *teles_status_buf = NULL;
-static byte    *teles_status_read = NULL;
-static byte    *teles_status_write = NULL;
-static byte    *teles_status_end = NULL;
-
-int
-teles_readstatus(byte * buf, int len, int user, int id, int channel)
-{
-	int             count;
-	byte           *p;
-
-	for (p = buf, count = 0; count < len; p++, count++) {
-		if (user)
-			put_user(*teles_status_read++, p);
-		else
-			*p++ = *teles_status_read++;
-		if (teles_status_read > teles_status_end)
-			teles_status_read = teles_status_buf;
-	}
-	return count;
-}
-
-void
-teles_putstatus(char *buf)
-{
-	long            flags;
-	int             len, count, i;
-	byte           *p;
-	isdn_ctrl       ic;
-
-	save_flags(flags);
-	cli();
-	count = 0;
-	len = strlen(buf);
-	for (p = buf, i = len; i > 0; i--, p++) {
-		*teles_status_write++ = *p;
-		if (teles_status_write > teles_status_end)
-			teles_status_write = teles_status_buf;
-		count++;
-	}
-	restore_flags(flags);
-	if (count) {
-		ic.command = ISDN_STAT_STAVAIL;
-		ic.driver = drid;
-		ic.arg = count;
-		iif.statcallb(&ic);
-	}
-}
-
-
-int
-ll_init(void)
-{
-	isdn_ctrl       ic;
-
-	teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE,
-				   GFP_KERNEL, "teles_status_buf");
-	if (!teles_status_buf) {
-		printk(KERN_ERR "teles: Could not allocate status-buffer\n");
-		return (-EIO);
-	} else {
-		teles_status_read = teles_status_buf;
-		teles_status_write = teles_status_buf;
-		teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1;
-	}
-
-	iif.channels = CallcNewChan();
-	iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
-	iif.features =
-	    ISDN_FEATURE_L2_X75I |
-	    ISDN_FEATURE_L2_HDLC |
-	    ISDN_FEATURE_L2_TRANS |
-	    ISDN_FEATURE_L3_TRANS |
-	    ISDN_FEATURE_P_1TR6 |
-	    ISDN_FEATURE_P_EURO;
-
-	iif.command = teles_command;
-	iif.writebuf = teles_writebuf;
-	iif.writecmd = NULL;
-	iif.readstat = teles_readstatus;
-	strncpy(iif.id, teles_id, sizeof(iif.id) - 1);
-
-	register_isdn(&iif);
-	drid = iif.channels;
-
-	ic.driver = drid;
-	ic.command = ISDN_STAT_RUN;
-	iif.statcallb(&ic);
-	return 0;
-}
-
-void
-ll_stop(void)
-{
-	isdn_ctrl       ic;
-
-	ic.command = ISDN_STAT_STOP;
-	ic.driver = drid;
-	iif.statcallb(&ic);
-
-	CallcFreeChan();
-}
-
-void
-ll_unload(void)
-{
-	isdn_ctrl       ic;
-
-	ic.command = ISDN_STAT_UNLOAD;
-	ic.driver = drid;
-	iif.statcallb(&ic);
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/mod.c linux/drivers/isdn/teles/mod.c
--- v2.1.36/linux/drivers/isdn/teles/mod.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/mod.c	Wed Dec 31 16:00:00 1969
@@ -1,160 +0,0 @@
-/* $Id: mod.c,v 1.3 1997/02/14 12:23:31 fritz Exp $
- *
- * $Log: mod.c,v $
- * Revision 1.3  1997/02/14 12:23:31  fritz
- * Added support for new insmod parameter handling.
- *
- * Revision 1.2  1997/02/10 11:45:14  fritz
- * More changes for Kernel 2.1.X compatibility.
- *
- * Revision 1.1  1996/04/13 10:27:02  fritz
- * Initial revision
- *
- *
- */
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern char   *teles_id;
-
-int             nrcards;
-
-typedef struct {
-	byte           *membase;
-	int             interrupt;
-	unsigned int    iobase;
-	unsigned int    protocol;
-} io_type;
-
-io_type         io[] =
-{
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-};
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE > 0x020111)
-MODULE_PARM(io, "1-64i");
-MODULE_PARM(teles_id, "s");
-#endif
-#endif
-
-void
-teles_mod_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-void
-teles_mod_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-#ifdef MODULE
-#define teles_init init_module
-#else
-void teles_setup(char *str, int *ints)
-{
-        int  i, j, argc;
-	static char sid[20];
-
-        argc = ints[0];
-        i = 0;
-        j = 1;
-        while (argc && (i<16)) {
-                if (argc) {
-                        io[i].iobase    = ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].interrupt = ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].membase   = (byte *)ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].protocol  = ints[j];
-                        j++; argc--;
-                }
-                i++;
-        }
-	if (strlen(str)) {
-		strcpy(sid,str);
-		teles_id = sid;
-	}
-}
-#endif
-
-int
-teles_init(void)
-{
-	int             i;
-
-	nrcards = 0;
-	for (i = 0; i < 16; i++) {
-		if (io[i].protocol) {
-			cards[i].membase   = io[i].membase;
-			cards[i].interrupt = io[i].interrupt;
-			cards[i].iobase    = io[i].iobase;
-			cards[i].protocol  = io[i].protocol;
-		}
-	}
-	for (i = 0; i < 16; i++)
-                if (cards[i].protocol)
-                        nrcards++;
-	printk(KERN_DEBUG "teles: Total %d card%s defined\n",
-               nrcards, (nrcards > 1) ? "s" : "");
-	if (teles_inithardware()) {
-                /* Install only, if at least one card found */
-                Isdnl2New();
-                TeiNew();
-                CallcNew();
-                ll_init();
-
-		/* No symbols to export, hide all symbols */
-
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < 0x020111)
-			register_symtab(NULL);
-#else
-			EXPORT_NO_SYMBOLS;
-#endif
-                printk(KERN_NOTICE "Teles module installed\n");
-#endif
-                return (0);
-        } else
-                return -EIO;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-
-	ll_stop();
-	TeiFree();
-	Isdnl2Free();
-	CallcFree();
-	teles_closehardware();
-	ll_unload();
-	printk(KERN_NOTICE "Teles module removed\n");
-
-}
-#endif
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/proto.h linux/drivers/isdn/teles/proto.h
--- v2.1.36/linux/drivers/isdn/teles/proto.h	Fri Nov 15 02:51:02 1996
+++ linux/drivers/isdn/teles/proto.h	Wed Dec 31 16:00:00 1969
@@ -1,18 +0,0 @@
-/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
- *
- * not much now - just the l3 proto discriminator
- *
- * $Log: proto.h,v $
- * Revision 1.1  1996/09/23 01:53:52  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- */
-
-#ifndef	PROTO_H
-#define	PROTO_H
-
-#define	PROTO_EURO		0x08
-#define	PROTO_DIS_N0	0x40
-#define	PROTO_DIS_N1	0x41
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c
--- v2.1.36/linux/drivers/isdn/teles/q931.c	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/q931.c	Wed Dec 31 16:00:00 1969
@@ -1,1155 +0,0 @@
-/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
- *
- * q931.c               code to decode ITU Q.931 call control messages
- * 
- * Author               Jan den Ouden
- * 
- * Changelog
- * 
- * Pauline Middelink    general improvements
- * 
- * Beat Doebeli         cause texts, display information element
- * 
- * Karsten Keil         cause texts, display information element for 1TR6 
- *
- * 
- * $Log: q931.c,v $
- * Revision 1.6  1996/09/23 01:53:53  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.5  1996/06/03 20:03:40  fritz
- * Fixed typos.
- *
- * Revision 1.4  1996/05/17 03:46:17  fritz
- * General cleanup.
- *
- * Revision 1.3  1996/04/30 22:06:50  isdn4dev
- *   logging 1TR6 messages correctly   Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:48:19  fritz
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:27:49  fritz
- * Initial revision
- *
- *
- */
-
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-#include "l3_1TR6.h"
-
-byte           *
-findie(byte * p, int size, byte ie, int wanted_set)
-{
-	int             l, codeset, maincodeset;
-	byte           *pend = p + size;
-
-	/* skip protocol discriminator, callref and message type */
-	p++;
-	l = (*p++) & 0xf;
-	p += l;
-	p++;
-	codeset = 0;
-	maincodeset = 0;
-	/* while there are bytes left... */
-	while (p < pend) {
-		if ((*p & 0xf0) == 0x90) {
-			codeset = *p & 0x07;
-			if (!(*p & 0x08))
-				maincodeset = codeset;
-		}
-		if (*p & 0x80)
-			p++;
-		else {
-			if (codeset == wanted_set) {
-				if (*p == ie)
-					return (p);
-				if (*p > ie)
-					return (NULL);
-			}
-			p++;
-			l = *p++;
-			p += l;
-			codeset = maincodeset;
-		}
-	}
-	return (NULL);
-}
-
-void
-iecpy(byte * dest, byte * iestart, int ieoffset)
-{
-	byte           *p;
-	int             l;
-
-	p = iestart + ieoffset + 2;
-	l = iestart[1] - ieoffset;
-	while (l--)
-		*dest++ = *p++;
-	*dest++ = '\0';
-}
-
-int
-getcallref(byte * p)
-{
-	p++;			/* prot discr */
-	p++;			/* callref length */
-	return (*p);		/* assuming one-byte callref */
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
-	byte            nr;
-	char           *descr;
-} mtlist[] = {
-
-	{
-		0x1, "ALERTING"
-	},
-	{
-		0x2, "CALL PROCEEDING"
-	},
-	{
-		0x7, "CONNECT"
-	},
-	{
-		0xf, "CONNECT ACKNOWLEDGE"
-	},
-	{
-		0x3, "PROGRESS"
-	},
-	{
-		0x5, "SETUP"
-	},
-	{
-		0xd, "SETUP ACKNOWLEDGE"
-	},
-	{
-		0x26, "RESUME"
-	},
-	{
-		0x2e, "RESUME ACKNOWLEDGE"
-	},
-	{
-		0x22, "RESUME REJECT"
-	},
-	{
-		0x25, "SUSPEND"
-	},
-	{
-		0x2d, "SUSPEND ACKNOWLEDGE"
-	},
-	{
-		0x21, "SUSPEND REJECT"
-	},
-	{
-		0x20, "USER INFORMATION"
-	},
-	{
-		0x45, "DISCONNECT"
-	},
-	{
-		0x4d, "RELEASE"
-	},
-	{
-		0x5a, "RELEASE COMPLETE"
-	},
-	{
-		0x46, "RESTART"
-	},
-	{
-		0x4e, "RESTART ACKNOWLEDGE"
-	},
-	{
-		0x60, "SEGMENT"
-	},
-	{
-		0x79, "CONGESTION CONTROL"
-	},
-	{
-		0x7b, "INFORMATION"
-	},
-	{
-		0x62, "FACILITY"
-	},
-	{
-		0x6e, "NOTIFY"
-	},
-	{
-		0x7d, "STATUS"
-	},
-	{
-		0x75, "STATUS ENQUIRY"
-	}
-};
-
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
-
-static
-struct MessageType mt_n0[] =
-{
-	{MT_N0_REG_IND, "REGister INDication"},
-	{MT_N0_CANC_IND, "CANCel INDication"},
-	{MT_N0_FAC_STA, "FACility STAtus"},
-	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
-	{MT_N0_STA_REJ, "STAtus REJect"},
-	{MT_N0_FAC_INF, "FACility INFormation"},
-	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
-	{MT_N0_INF_REJ, "INFormation REJect"},
-	{MT_N0_CLOSE, "CLOSE"},
-	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
-
-static
-struct MessageType mt_n1[] =
-{
-	{MT_N1_ESC, "ESCape"},
-	{MT_N1_ALERT, "ALERT"},
-	{MT_N1_CALL_SENT, "CALL SENT"},
-	{MT_N1_CONN, "CONNect"},
-	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
-	{MT_N1_SETUP, "SETUP"},
-	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
-	{MT_N1_RES, "RESume"},
-	{MT_N1_RES_ACK, "RESume ACKnowledge"},
-	{MT_N1_RES_REJ, "RESume REJect"},
-	{MT_N1_SUSP, "SUSPend"},
-	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
-	{MT_N1_SUSP_REJ, "SUSPend REJect"},
-	{MT_N1_USER_INFO, "USER INFO"},
-	{MT_N1_DET, "DETach"},
-	{MT_N1_DISC, "DISConnect"},
-	{MT_N1_REL, "RELease"},
-	{MT_N1_REL_ACK, "RELease ACKnowledge"},
-	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
-	{MT_N1_CANC_REJ, "CANCel REJect"},
-	{MT_N1_CON_CON, "CONgestion CONtrol"},
-	{MT_N1_FAC, "FACility"},
-	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
-	{MT_N1_FAC_CAN, "FACility CANcel"},
-	{MT_N1_FAC_REG, "FACility REGister"},
-	{MT_N1_FAC_REJ, "FACility REJect"},
-	{MT_N1_INFO, "INFOrmation"},
-	{MT_N1_REG_ACK, "REGister ACKnowledge"},
-	{MT_N1_REG_REJ, "REGister REJect"},
-	{MT_N1_STAT, "STATus"}
-};
-
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
-
-static struct MessageType fac_1tr6[] =
-{
-	{FAC_Sperre, "Sperre"},
-	{FAC_Forward1, "Forward 1"},
-	{FAC_Forward2, "Forward 2"},
-	{FAC_Konferenz, "Konferenz"},
-	{FAC_GrabBchan, "Grab Bchannel"},
-	{FAC_Reactivate, "Reactivate"},
-	{FAC_Konferenz3, "Dreier Konferenz"},
-	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
-	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
-	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
-	{FAC_GBG, "GBG"},
-	{FAC_DisplayUebergeben, "Display Uebergeben"},
-	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
-	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
-	{FAC_Deactivate, "Deactivate"},
-	{FAC_Activate, "Activate"},
-	{FAC_SPV, "SPV"},
-	{FAC_Rueckwechsel, "Rueckwechsel"},
-	{FAC_Umleitung, "Umleitung"}
-};
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
-
-static int 
-prbits(char *dest, byte b, int start, int len)
-{
-	char           *dp = dest;
-
-	b = b << (8 - start);
-	while (len--) {
-		if (b & 0x80)
-			*dp++ = '1';
-		else
-			*dp++ = '0';
-		b = b << 1;
-	}
-	return (dp - dest);
-}
-
-static
-byte           *
-skipext(byte * p)
-{
-	while (!(*p++ & 0x80));
-	return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- *         not yet written...
- */
-
-static
-struct CauseValue {
-	byte            nr;
-	char           *edescr;
-	char           *ddescr;
-} cvlist[] = {
-
-	{
-		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
-	},
-	{
-		0x02, "No route to specified transit network", ""
-	},
-	{
-		0x03, "No route to destination", ""
-	},
-	{
-		0x04, "Send special information tone", ""
-	},
-	{
-		0x05, "Misdialled trunk prefix", ""
-	},
-	{
-		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
-	},
-	{
-		0x07, "Channel awarded and being delivered in an established channel", ""
-	},
-	{
-		0x08, "Preemption", ""
-	},
-	{
-		0x09, "Preemption - circuit reserved for reuse", ""
-	},
-	{
-		0x10, "Normal call clearing", "Normale Ausloesung"
-	},
-	{
-		0x11, "User busy", "TNB besetzt"
-	},
-	{
-		0x12, "No user responding", ""
-	},
-	{
-		0x13, "No answer from user (user alerted)", ""
-	},
-	{
-		0x14, "Subscriber absent", ""
-	},
-	{
-		0x15, "Call rejected", ""
-	},
-	{
-		0x16, "Number changed", ""
-	},
-	{
-		0x1a, "non-selected user clearing", ""
-	},
-	{
-		0x1b, "Destination out of order", ""
-	},
-	{
-		0x1c, "Invalid number format (address incomplete)", ""
-	},
-	{
-		0x1d, "Facility rejected", ""
-	},
-	{
-		0x1e, "Response to Status enquiry", ""
-	},
-	{
-		0x1f, "Normal, unspecified", ""
-	},
-	{
-		0x22, "No circuit/channel available", ""
-	},
-	{
-		0x26, "Network out of order", ""
-	},
-	{
-		0x27, "Permanent frame mode connection out-of-service", ""
-	},
-	{
-		0x28, "Permanent frame mode connection operational", ""
-	},
-	{
-		0x29, "Temporary failure", ""
-	},
-	{
-		0x2a, "Switching equipment congestion", ""
-	},
-	{
-		0x2b, "Access information discarded", ""
-	},
-	{
-		0x2c, "Requested circuit/channel not available", ""
-	},
-	{
-		0x2e, "Precedence call blocked", ""
-	},
-	{
-		0x2f, "Resource unavailable, unspecified", ""
-	},
-	{
-		0x31, "Quality of service unavailable", ""
-	},
-	{
-		0x32, "Requested facility not subscribed", ""
-	},
-	{
-		0x35, "Outgoing calls barred within CUG", ""
-	},
-	{
-		0x37, "Incoming calls barred within CUG", ""
-	},
-	{
-		0x39, "Bearer capability not authorized", ""
-	},
-	{
-		0x3a, "Bearer capability not presently available", ""
-	},
-	{
-		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
-	},
-	{
-		0x3f, "Service or option not available, unspecified", ""
-	},
-	{
-		0x41, "Bearer capability not implemented", ""
-	},
-	{
-		0x42, "Channel type not implemented", ""
-	},
-	{
-		0x43, "Requested facility not implemented", ""
-	},
-	{
-		0x44, "Only restricted digital information bearer capability is available", ""
-	},
-	{
-		0x4f, "Service or option not implemented", ""
-	},
-	{
-		0x51, "Invalid call reference value", ""
-	},
-	{
-		0x52, "Identified channel does not exist", ""
-	},
-	{
-		0x53, "A suspended call exists, but this call identity does not", ""
-	},
-	{
-		0x54, "Call identity in use", ""
-	},
-	{
-		0x55, "No call suspended", ""
-	},
-	{
-		0x56, "Call having the requested call identity has been cleared", ""
-	},
-	{
-		0x57, "User not member of CUG", ""
-	},
-	{
-		0x58, "Incompatible destination", ""
-	},
-	{
-		0x5a, "Non-existent CUG", ""
-	},
-	{
-		0x5b, "Invalid transit network selection", ""
-	},
-	{
-		0x5f, "Invalid message, unspecified", ""
-	},
-	{
-		0x60, "Mandatory information element is missing", ""
-	},
-	{
-		0x61, "Message type non-existent or not implemented", ""
-	},
-	{
-		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
-	},
-	{
-		0x63, "Information element/parameter non-existent or not implemented", ""
-	},
-	{
-		0x64, "Invalid information element contents", ""
-	},
-	{
-		0x65, "Message not compatible with call state", ""
-	},
-	{
-		0x66, "Recovery on timer expiry", ""
-	},
-	{
-		0x67, "Parameter non-existent or not implemented - passed on", ""
-	},
-	{
-		0x6e, "Message with unrecognized parameter discarded", ""
-	},
-	{
-		0x6f, "Protocol error, unspecified", ""
-	},
-	{
-		0x7f, "Interworking, unspecified", ""
-	},
-};
-
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
-
-static
-int
-prcause(char *dest, byte * p)
-{
-	byte           *end;
-	char           *dp = dest;
-	int             i, cause;
-
-	end = p + p[1] + 1;
-	p += 2;
-	dp += sprintf(dp, "    coding ");
-	dp += prbits(dp, *p, 7, 2);
-	dp += sprintf(dp, " location ");
-	dp += prbits(dp, *p, 4, 4);
-	*dp++ = '\n';
-	p = skipext(p);
-
-	cause = 0x7f & *p++;
-
-	/* locate cause value */
-	for (i = 0; i < CVSIZE; i++)
-		if (cvlist[i].nr == cause)
-			break;
-
-	/* display cause value if it exists */
-	if (i == CVSIZE)
-		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
-	else
-		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
-
-	while (!0) {
-		if (p > end)
-			break;
-		dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
-		dp += sprintf(dp, " rej %d ", *p & 0x7f);
-		if (*p & 0x80) {
-			*dp++ = '\n';
-			break;
-		} else
-			dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
-	}
-	return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
-	{CAUSE_InvCRef, "Invalid Call Reference"},
-	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
-	{CAUSE_CIDunknown, "Caller Identity unknown"},
-	{CAUSE_CIDinUse, "Caller Identity in Use"},
-	{CAUSE_NoChans, "No Channels available"},
-	{CAUSE_FacNotImpl, "Facility Not Implemented"},
-	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
-	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
-	{CAUSE_UserAccessBusy, "User Access Busy"},
-	{CAUSE_NegativeGBG, "Negative GBG"},
-	{CAUSE_UnknownGBG, "Unknown  GBG"},
-	{CAUSE_NoSPVknown, "No SPV known"},
-	{CAUSE_DestNotObtain, "Destination not obtainable"},
-	{CAUSE_NumberChanged, "Number changed"},
-	{CAUSE_OutOfOrder, "Out Of Order"},
-	{CAUSE_NoUserResponse, "No User Response"},
-	{CAUSE_UserBusy, "User Busy"},
-	{CAUSE_IncomingBarred, "Incoming Barred"},
-	{CAUSE_CallRejected, "Call Rejected"},
-	{CAUSE_NetworkCongestion, "Network Congestion"},
-	{CAUSE_RemoteUser, "Remote User initiated"},
-	{CAUSE_LocalProcErr, "Local Procedure Error"},
-	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
-	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
-	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
-	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
-
-static int
-prcause_1tr6(char *dest, byte * p) 
-{
-	char           *dp = dest;
-	int i, cause;
-
-	p++;
-	if (0 == *p) {
-		dp += sprintf(dp, "   OK (cause length=0)\n");
-		return (dp - dest);
-	} else if (*p > 1) {
-		dp += sprintf(dp, "    coding ");
-		dp += prbits(dp, p[2], 7, 2);
-		dp += sprintf(dp, " location ");
-		dp += prbits(dp, p[2], 4, 4);
-		*dp++ = '\n';
-	}
-	p++;
-	cause = 0x7f & *p;
-
-	/* locate cause value */
-	for (i = 0; i < cause_1tr6_len; i++)
-		if (cause_1tr6[i].nr == cause)
-			break;
-
-	/* display cause value if it exists */
-	if (i == cause_1tr6_len)
-		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
-	else
-		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
-	return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, byte * p) {
-	char *dp = dest;
-
-	p += 2;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-static int
-prcalled(char *dest, byte * p) {
-	int             l;
-	char           *dp = dest;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p++, 8, 8);
-	*dp++ = '\n';
-	dp += sprintf(dp, "    number digits ");
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-static int
-prcalling(char *dest, byte * p) {
-	int             l;
-	char           *dp = dest;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	if (!(*p & 0x80)) {
-		dp += sprintf(dp, "    octet 3a ");
-		dp += prbits(dp, *++p, 8, 8);
-		*dp++ = '\n';
-		l--;
-	};
-	p++;
-
-	dp += sprintf(dp, "    number digits ");
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, byte * p)
-{
-	char           *dp = dest, ch;
-
-	p += 2;
-	dp += sprintf(dp, "    octet 3  ");
-	dp += prbits(dp, *p++, 8, 8);
-	*dp++ = '\n';
-	dp += sprintf(dp, "    octet 4  ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	if ((*p++ & 0x1f) == 0x18) {
-		dp += sprintf(dp, "    octet 4.1 ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	/* check for user information layer 1 */
-	if ((*p & 0x60) == 0x20) {
-		ch = ' ';
-		do {
-			dp += sprintf(dp, "    octet 5%c ", ch);
-			dp += prbits(dp, *p, 8, 8);
-			*dp++ = '\n';
-			if (ch == ' ')
-				ch = 'a';
-			else
-				ch++;
-		}
-		while (!(*p++ & 0x80));
-	}
-	/* check for user information layer 2 */
-	if ((*p & 0x60) == 0x40) {
-		dp += sprintf(dp, "    octet 6  ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	/* check for user information layer 3 */
-	if ((*p & 0x60) == 0x60) {
-		dp += sprintf(dp, "    octet 7  ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	return (dp - dest);
-}
-
-static int
-general(char *dest, byte * p) {
-	char           *dp = dest;
-	char            ch = ' ';
-	int             l, octet = 3;
-
-	p++;
-	l = *p++;
-	/* Iterate over all octets in the information element */
-	while (l--) {
-		dp += sprintf(dp, "    octet %d%c ", octet, ch);
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-
-		/* last octet in group? */
-		if (*p & 0x80) {
-			octet++;
-			ch = ' ';
-		} else if (ch == ' ')
-			ch = 'a';
-		else
-			ch++;
-	}
-	return (dp - dest);
-}
-
-static int
-prcharge(char *dest, byte * p) {
-	char *dp = dest;
-	int l;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    GEA ");
-	dp += prbits(dp, *p++, 8, 8);
-	dp += sprintf(dp, "  Anzahl: ");
-	/* Iterate over all octets in the * information element */
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-} 
-static int
-prtext(char *dest, byte * p) {
-	char *dp = dest;
-	int l;
-
-	p++;
-	l = *p++;
-	dp += sprintf(dp, "    ");
-	/* Iterate over all octets in the * information element */
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-static int
-display(char *dest, byte * p) {
-	char           *dp = dest;
-	char            ch = ' ';
-	int             l, octet = 3;
-
-	p++;
-	l = *p++;
-	/* Iterate over all octets in the * display-information element */
-	dp += sprintf(dp, "   \"");
-	while (l--) {
-		dp += sprintf(dp, "%c", *p++);
-
-		/* last octet in group? */
-		if (*p & 0x80) {
-			octet++;
-			ch = ' ';
-		} else if (ch == ' ')
-			ch = 'a';
-
-		else
-			ch++;
-	}
-	*dp++ = '\"';
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-int
-prfacility(char *dest, byte * p)
-{
-	char           *dp = dest;
-	int             l, l2;
-
-	p++;
-	l = *p++;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p++, 8, 8);
-	dp += sprintf(dp, "\n");
-	l -= 1;
-
-	while (l > 0) {
-		dp += sprintf(dp, "   octet 4 ");
-		dp += prbits(dp, *p++, 8, 8);
-		dp += sprintf(dp, "\n");
-		dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
-		l -= 2;
-		dp += sprintf(dp, "   contents ");
-		while (l2--) {
-			dp += sprintf(dp, "%2x ", *p++);
-			l--;
-		}
-		dp += sprintf(dp, "\n");
-	}
-
-	return (dp - dest);
-}
-
-static
-struct InformationElement {
-	byte            nr;
-	char           *descr;
-	int             (*f) (char *, byte *);
-} ielist[] = {
-
-	{
-		0x00, "Segmented message", general
-	},
-	{
-		0x04, "Bearer capability", prbearer
-	},
-	{
-		0x08, "Cause", prcause
-	},
-	{
-		0x10, "Call identity", general
-	},
-	{
-		0x14, "Call state", general
-	},
-	{
-		0x18, "Channel identification", prchident
-	},
-	{
-		0x1c, "Facility", prfacility
-	},
-	{
-		0x1e, "Progress indicator", general
-	},
-	{
-		0x20, "Network-specific facilities", general
-	},
-	{
-		0x27, "Notification indicator", general
-	},
-	{
-		0x28, "Display", display
-	},
-	{
-		0x29, "Date/Time", general
-	},
-	{
-		0x2c, "Keypad facility", general
-	},
-	{
-		0x34, "Signal", general
-	},
-	{
-		0x40, "Information rate", general
-	},
-	{
-		0x42, "End-to-end delay", general
-	},
-	{
-		0x43, "Transit delay selection and indication", general
-	},
-	{
-		0x44, "Packet layer binary parameters", general
-	},
-	{
-		0x45, "Packet layer window size", general
-	},
-	{
-		0x46, "Packet size", general
-	},
-	{
-		0x47, "Closed user group", general
-	},
-	{
-		0x4a, "Reverse charge indication", general
-	},
-	{
-		0x6c, "Calling party number", prcalling
-	},
-	{
-		0x6d, "Calling party subaddress", general
-	},
-	{
-		0x70, "Called party number", prcalled
-	},
-	{
-		0x71, "Called party subaddress", general
-	},
-	{
-		0x74, "Redirecting number", general
-	},
-	{
-		0x78, "Transit network selection", general
-	},
-	{
-		0x79, "Restart indicator", general
-	},
-	{
-		0x7c, "Low layer compatibility", general
-	},
-	{
-		0x7d, "High layer compatibility", general
-	},
-	{
-		0x7e, "User-user", general
-	},
-	{
-		0x7f, "Escape for extension", general
-	},
-};
-
-
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
-
-static struct InformationElement we_0[] =
-{
-	{WE0_cause, "Cause", prcause_1tr6},
-	{WE0_connAddr, "Connecting Address", prcalled},
-	{WE0_callID, "Call IDentity", general},
-	{WE0_chanID, "Channel IDentity", general},
-	{WE0_netSpecFac, "Network Specific Facility", general},
-	{WE0_display, "Display", general},
-	{WE0_keypad, "Keypad", general},
-	{WE0_origAddr, "Origination Address", prcalled},
-	{WE0_destAddr, "Destination Address", prcalled},
-	{WE0_userInfo, "User Info", general}
-};
-
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
-
-static struct InformationElement we_6[] =
-{
-	{WE6_serviceInd, "Service Indicator", general},
-	{WE6_chargingInfo, "Charging Information", prcharge},
-	{WE6_date, "Date", prtext},
-	{WE6_facSelect, "Facility Select", general},
-	{WE6_facStatus, "Facility Status", general},
-	{WE6_statusCalled, "Status Called", general},
-	{WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
-
-void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
-	byte           *bend = buf + size;
-	char           *dp;
-	int i, cs = 0, cs_old = 0, cs_fest = 0;
-
-	/* display header */
-	dp = sp->dlogspace;
-	dp += sprintf(dp, "%s\n", comment);
-
-	{
-		byte *p = buf;
-		dp += sprintf(dp, "hex: ");
-		while (p < bend)
-		dp += sprintf(dp, "%02x ", *p++);
-		dp += sprintf(dp, "\n");
-		teles_putstatus(sp->dlogspace);
-		dp = sp->dlogspace;
-	} 
-	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
-		/* locate message type */
-		if (buf[0] == PROTO_DIS_N0) {	/* N0 */
-			for (i = 0; i < mt_n0_len; i++)
-				if (mt_n0[i].nr == buf[3])
-					break;
-			/* display message type iff it exists */
-			if (i == mt_n0_len)
-				dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
-			else
-				dp += sprintf(dp, "call reference %d size %d message type %s\n",
-					      buf[2], size, mt_n0[i].descr);
-		} else {	/* N1 */
-			for (i = 0; i < mt_n1_len; i++)
-				if (mt_n1[i].nr == buf[3])
-					break;
-			/* display message type iff it exists */
-			if (i == mt_n1_len)
-				dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
-			else
-				dp += sprintf(dp, "call reference %d size %d message type %s\n",
-					      buf[2], size, mt_n1[i].descr);
-		}
-
-		/* display each information element */
-		buf += 4;
-		while (buf < bend) {
-			/* Is it a single octet information element? */
-			if (*buf & 0x80) {
-				switch ((*buf >> 4) & 7) {
-				  case 1:
-					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-					cs_old = cs;
-					cs = *buf & 7;
-					cs_fest = *buf & 8;
-					break;
-				  case 3:
-					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
-					break;
-				  case 2:
-					if (*buf == 0xa0) {
-						dp += sprintf(dp, "  More data\n");
-						break;
-					}
-					if (*buf == 0xa1) {
-						dp += sprintf(dp, "  Sending complete\n");
-					}
-					break;
-				  /* fall through */
-				  default:
-					dp += sprintf(dp, "  Reserved %x\n", *buf);
-					break;
-				}
-				buf++;
-				continue;
-			}
-			/* No, locate it in the table */
-			if (cs == 0) {
-				for (i = 0; i < we_0_len; i++)
-					if (*buf == we_0[i].nr)
-						break;
-
-				/* When found, give appropriate msg */
-				if (i != we_0_len) {
-					dp += sprintf(dp, "  %s\n", we_0[i].descr);
-					dp += we_0[i].f(dp, buf);
-				} else
-					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			} else if (cs == 6) {
-				for (i = 0; i < we_6_len; i++)
-					if (*buf == we_6[i].nr)
-						break;
-
-				/* When found, give appropriate msg */
-				if (i != we_6_len) {
-					dp += sprintf(dp, "  %s\n", we_6[i].descr);
-					dp += we_6[i].f(dp, buf);
-				} else
-					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			} else
-				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			/* Skip to next element */
-			if (cs_fest == 8) {
-				cs = cs_old;
-				cs_old = 0;
-				cs_fest = 0;
-			}
-			buf += buf[1] + 2;
-		}
-	} else if (buf[0]==PROTO_EURO) {	/* EURO */
-		/* locate message type */
-		for (i = 0; i < MTSIZE; i++)
-			if (mtlist[i].nr == buf[3])
-				break;
-
-		/* display message type iff it exists */
-		if (i == MTSIZE)
-			dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
-		else
-			dp += sprintf(dp, "call reference %d size %d message type %s\n",
-		buf[2], size, mtlist[i].descr);
-
-		/* display each information element */
-		buf += 4;
-		while (buf < bend) {
-			/* Is it a single octet information element? */
-			if (*buf & 0x80) {
-				switch ((*buf >> 4) & 7) {
-				  case 1:
-					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-					break;
-				  case 3:
-					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
-					break;
-				  case 5:
-					dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
-					break;
-				  case 2:
-					if (*buf == 0xa0) {
-						dp += sprintf(dp, "  More data\n");
-						break;
-					}
-					if (*buf == 0xa1) {
-						dp += sprintf(dp, "  Sending complete\n");
-					}
-					break;
-				  /* fall through */
-				  default:
-					dp += sprintf(dp, "  Reserved %x\n", *buf);
-					break;
-				}
-				buf++;
-				continue;
-			}
-			/* No, locate it in the table */
-			for (i = 0; i < IESIZE; i++)
-				if (*buf == ielist[i].nr)
-					break;
-
-			/* When not found, give appropriate msg */
-			if (i != IESIZE) {
-				dp += sprintf(dp, "  %s\n", ielist[i].descr);
-				dp += ielist[i].f(dp, buf);
-			} else
-				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
-
-			/* Skip to next element */
-			buf += buf[1] + 2;
-		}
-	}
-	else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
-
-	dp += sprintf(dp, "\n");
-	teles_putstatus(sp->dlogspace);
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/tei.c linux/drivers/isdn/teles/tei.c
--- v2.1.36/linux/drivers/isdn/teles/tei.c	Sun Apr 21 01:56:15 1996
+++ linux/drivers/isdn/teles/tei.c	Wed Dec 31 16:00:00 1969
@@ -1,248 +0,0 @@
-/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $
- *
- * $Log: tei.c,v $
- * Revision 1.1  1996/04/13 10:28:25  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int      nrcards;
-
-static struct PStack *
-findces(struct PStack *st, int ces)
-{
-	struct PStack  *ptr = *(st->l1.stlistp);
-
-	while (ptr)
-		if (ptr->l2.ces == ces)
-			return (ptr);
-		else
-			ptr = ptr->next;
-	return (NULL);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
-	struct PStack  *ptr = *(st->l1.stlistp);
-
-	if (tei == 127)
-		return (NULL);
-
-	while (ptr)
-		if (ptr->l2.tei == tei)
-			return (ptr);
-		else
-			ptr = ptr->next;
-	return (NULL);
-}
-
-void 
-tei_handler(struct PStack *st,
-	    byte pr, struct BufHeader *ibh)
-{
-	byte           *bp;
-	unsigned int    tces;
-	struct PStack  *otsp, *ptr;
-	unsigned int    data;
-
-	if (st->l2.debug)
-		printk(KERN_DEBUG "teihandler %d\n", pr);
-
-	switch (pr) {
-	  case (MDL_ASSIGN):
-		  data = (unsigned int) ibh;
-		  BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
-		  if (!ibh)
-			  return;
-		  bp = DATAPTR(ibh);
-		  bp += st->l2.uihsize;
-		  bp[0] = 0xf;
-		  bp[1] = data >> 8;
-		  bp[2] = data & 0xff;
-		  bp[3] = 0x1;
-		  bp[4] = 0xff;
-		  ibh->datasize = 8;
-		  st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-		  break;
-	  case (DL_UNIT_DATA):
-		  bp = DATAPTR(ibh);
-		  bp += 3;
-		  if (bp[0] != 0xf)
-			  break;
-		  switch (bp[3]) {
-		    case (2):
-			    tces = (bp[1] << 8) | bp[2];
-			    BufPoolRelease(ibh);
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
-					   bp[4] >> 1);
-			    if ((otsp = findces(st, tces)))
-				    otsp->ma.teil2(otsp, MDL_ASSIGN,
-						   (void *)(bp[4] >> 1));
-			    break;
-		    case (4):
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
-			    if (bp[4] >> 1 == 0x7f) {
-				    BufPoolRelease(ibh);
-				    ptr = *(st->l1.stlistp);
-				    while (ptr) {
-					    if ((ptr->l2.tei & 0x7f) != 0x7f) {
-						    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
-							    break;
-						    bp = DATAPTR(ibh);
-						    bp += 3;
-						    bp[0] = 0xf;
-						    bp[1] = ptr->l2.ces >> 8;
-						    bp[2] = ptr->l2.ces & 0xff;
-						    bp[3] = 0x5;
-						    bp[4] = (ptr->l2.tei << 1) | 1;
-						    ibh->datasize = 8;
-						    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-					    }
-					    ptr = ptr->next;
-				    }
-			    } else {
-				    otsp = findtei(st, bp[4] >> 1);
-				    BufPoolRelease(ibh);
-				    if (!otsp)
-					    break;
-				    if (st->l3.debug)
-					    printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
-				    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
-					    break;
-				    bp = DATAPTR(ibh);
-				    bp += 3;
-				    bp[0] = 0xf;
-				    bp[1] = otsp->l2.ces >> 8;
-				    bp[2] = otsp->l2.ces & 0xff;
-				    bp[3] = 0x5;
-				    bp[4] = (otsp->l2.tei << 1) | 1;
-				    ibh->datasize = 8;
-				    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-			    }
-			    break;
-		    default:
-			    BufPoolRelease(ibh);
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
-		  }
-		  break;
-	  default:
-		  printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
-		  break;
-	}
-}
-
-unsigned int 
-randomces(void)
-{
-	int             x = jiffies & 0xffff;
-
-	return (x);
-}
-
-static void 
-tei_man(struct PStack *sp, int i, void *v)
-{
-	printk(KERN_DEBUG "tei_man\n");
-}
-
-static void 
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
-	struct IsdnCardState *sp = st->l1.hardware;
-
-	tei_handler(sp->teistack, pr, arg);
-}
-
-void 
-setstack_tei(struct PStack *st)
-{
-	st->l2.l2tei = tei_l2tei;
-}
-
-static void 
-init_tei(struct IsdnCardState *sp, int protocol)
-{
-	struct PStack  *st;
-	char            tmp[128];
-
-#define DIRTY_HACK_AGAINST_SIGSEGV
-
-	st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
-				       "struct PStack");
-
-#ifdef DIRTY_HACK_AGAINST_SIGSEGV
-	sp->teistack = st;	                /* struct is not initialized yet */
-	sp->teistack->protocol = protocol;	/* struct is not initialized yet */
-#endif	                                        /* DIRTY_HACK_AGAINST_SIGSEGV    */
-
-
-	setstack_teles(st, sp);
-
-	st->l2.extended = !0;
-	st->l2.laptype = LAPD;
-	st->l2.window = 1;
-	st->l2.orig = !0;
-	st->protocol = protocol;
-
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
-
-	st->l2.t200 = 500;	/* 500 milliseconds */
-	st->l2.n200 = 4;	/* try 4 times */
-
-	st->l2.sap = 63;
-	st->l2.tei = 127;
-
-	sprintf(tmp, "Card %d tei ", sp->cardnr);
-	setstack_isdnl2(st, tmp);
-	st->l2.debug = 0;
-	st->l3.debug = 0;
-
-	st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-
-	st->l2.l2l3 = (void *) tei_handler;
-	st->l1.l1man = tei_man;
-	st->l2.l2man = tei_man;
-	st->l4.l2writewakeup = NULL;
-	
-	teles_addlist(sp, st);
-	sp->teistack = st;
-}
-
-static void 
-release_tei(struct IsdnCardState *sp)
-{
-	struct PStack  *st = sp->teistack;
-
-	teles_rmlist(sp, st);
-	Sfree((void *) st);
-}
-
-void 
-TeiNew(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp)
-			init_tei(cards[i].sp, cards[i].protocol);
-}
-
-void 
-TeiFree(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp)
-			release_tei(cards[i].sp);
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/teles.h linux/drivers/isdn/teles/teles.h
--- v2.1.36/linux/drivers/isdn/teles/teles.h	Thu Feb 27 10:57:30 1997
+++ linux/drivers/isdn/teles/teles.h	Wed Dec 31 16:00:00 1969
@@ -1,486 +0,0 @@
-/* $Id: teles.h,v 1.3 1997/02/11 01:40:36 keil Exp $
- *
- * $Log: teles.h,v $
- * Revision 1.3  1997/02/11 01:40:36  keil
- * New Param structure
- *
- * Revision 1.2  1996/04/30 21:52:04  isdn4dev
- * SPV for 1TR6 - Karsten
- *
- * Revision 1.1  1996/04/13 10:29:00  fritz
- * Initial revision
- *
- *
- */
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-#include <linux/tty.h>
-
-#define PH_ACTIVATE   1
-#define PH_DATA       2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN       4
-#define DL_UNIT_DATA     5
-#define SC_STARTUP       6
-#define CC_ESTABLISH     7
-#define DL_ESTABLISH     8
-#define DL_DATA          9
-#define CC_S_STATUS_ENQ  10
-
-#define CC_CONNECT       15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF                 17
-#define SC_DISCONNECT          18
-#define CO_DTMF                19
-#define DL_RELEASE             20
-
-#define CO_ALARM               22
-#define CC_REJECT              23
-
-#define CC_SETUP_REQ           24
-#define CC_SETUP_CNF           25
-#define CC_SETUP_IND           26
-#define CC_SETUP_RSP           27
-#define CC_SETUP_COMPLETE_IND  28
-
-#define CC_DISCONNECT_REQ      29
-#define CC_DISCONNECT_IND      30
-
-#define CC_RELEASE_CNF         31
-#define CC_RELEASE_IND         32
-#define CC_RELEASE_REQ         33
-
-#define CC_REJECT_REQ          34
-
-#define CC_PROCEEDING_IND      35
-
-#define CC_DLRL                36
-#define CC_DLEST               37
-
-#define CC_ALERTING_REQ        38
-#define CC_ALERTING_IND        39
-
-#define DL_STOP                40
-#define DL_START               41
-
-#define MDL_NOTEIPROC          46
-
-#define LC_ESTABLISH           47
-#define LC_RELEASE             48
-
-#define PH_REQUEST_PULL        49
-#define PH_PULL_ACK            50
-#define	PH_DATA_PULLED	       51
-#define CC_INFO_CHARGE         52
-
-/*
- * Message-Types 
- */
-
-#define MT_ALERTING            0x01
-#define MT_CALL_PROCEEDING     0x02
-#define MT_CONNECT             0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS            0x03
-#define MT_SETUP               0x05
-#define MT_SETUP_ACKNOWLEDGE   0x0d
-#define MT_RESUME              0x26
-#define MT_RESUME_ACKNOWLEDGE  0x2e
-#define MT_RESUME_REJECT       0x22
-#define MT_SUSPEND             0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT      0x21
-#define MT_USER_INFORMATION    0x20
-#define MT_DISCONNECT          0x45
-#define MT_RELEASE             0x4d
-#define MT_RELEASE_COMPLETE    0x5a
-#define MT_RESTART             0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT             0x60
-#define MT_CONGESTION_CONTROL  0x79
-#define MT_INFORMATION         0x7b
-#define MT_FACILITY            0x62
-#define MT_NOTIFY              0x6e
-#define MT_STATUS              0x7d
-#define MT_STATUS_ENQUIRY      0x75
-
-#define IE_CAUSE               0x08
-
-struct HscxIoctlArg {
-	int             channel;
-	int             mode;
-	int             transbufsize;
-};
-
-#ifdef __KERNEL__
-
-#undef DEBUG_MAGIC
-
-#define HSCX_SBUF_ORDER     1
-#define HSCX_SBUF_BPPS      2
-#define HSCX_SBUF_MAXPAGES  3
-
-#define HSCX_RBUF_ORDER     1
-#define HSCX_RBUF_BPPS      2
-#define HSCX_RBUF_MAXPAGES  3
-
-#define HSCX_SMALLBUF_ORDER     0
-#define HSCX_SMALLBUF_BPPS      40
-#define HSCX_SMALLBUF_MAXPAGES  1
-
-#define ISAC_SBUF_ORDER     0
-#define ISAC_SBUF_BPPS      16
-#define ISAC_SBUF_MAXPAGES  1
-
-#define ISAC_RBUF_ORDER     0
-#define ISAC_RBUF_BPPS      16
-#define ISAC_RBUF_MAXPAGES  1
-
-#define ISAC_SMALLBUF_ORDER     0
-#define ISAC_SMALLBUF_BPPS      40
-#define ISAC_SMALLBUF_MAXPAGES  1
-
-#define byte unsigned char
-
-#define MAX_WINDOW 8
-
-byte           *Smalloc(int size, int pr, char *why);
-void            Sfree(byte * ptr);
-
-/*
- * Statemachine 
- */
-struct Fsm {
-	int            *jumpmatrix;
-	int             state_count, event_count;
-	char          **strEvent, **strState;
-};
-
-struct FsmInst {
-	struct Fsm     *fsm;
-	int             state;
-	int             debug;
-	void           *userdata;
-	int             userint;
-	void            (*printdebug) (struct FsmInst *, char *);
-};
-
-struct FsmNode {
-	int             state, event;
-	void            (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
-	struct FsmInst *fi;
-	struct timer_list tl;
-	int             event;
-	void           *arg;
-};
-
-struct BufHeader {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *next;
-	struct BufPool *bp;
-	int             datasize;
-	byte            primitive, where;
-	void           *heldby;
-};
-
-struct Pages {
-	struct Pages   *next;
-};
-
-struct BufPool {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *freelist;
-	struct Pages   *pageslist;
-	int             pageorder;
-	int             pagescount;
-	int             bpps;
-	int             bufsize;
-	int             maxpages;
-};
-
-struct BufQueue {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *head, *tail;
-};
-
-struct Layer1 {
-	void           *hardware;
-	int             hscx;
-	struct BufPool *sbufpool, *rbufpool, *smallpool;
-	struct PStack **stlistp;
-	int             act_state;
-	void            (*l1l2) (struct PStack *, int, struct BufHeader *);
-        void            (*l1man) (struct PStack *, int, void *);
-	int             hscxmode, hscxchannel, requestpull;
-};
-
-struct Layer2 {
-	int             sap, tei, ces;
-	int             extended, laptype;
-	int             uihsize, ihsize;
-	int             vs, va, vr;
-	struct BufQueue i_queue;
-	int             window, orig;
-	int             rejexp;
-	int             debug;
-	struct BufHeader *windowar[MAX_WINDOW];
-	int             sow;
-	struct FsmInst  l2m;
-	void            (*l2l1) (struct PStack *, int, struct BufHeader *);
-        void            (*l2l1discardq) (struct PStack *, int, void *, int);
-        void            (*l2man) (struct PStack *, int, void *);
-	void            (*l2l3) (struct PStack *, int, void *);
-	void            (*l2tei) (struct PStack *, int, void *);
-	struct FsmTimer t200_timer, t203_timer;
-	int             t200, n200, t203;
-	int             rc, t200_running;
-	char            debug_id[32];
-};
-
-struct Layer3 {
-	void            (*l3l4) (struct PStack *, int, struct BufHeader *);
-        void            (*l3l2) (struct PStack *, int, void *);
-	int             state, callref;
-	int             debug;
-};
-
-struct Layer4 {
-	void            (*l4l3) (struct PStack *, int, void *);
-	void           *userdata;
-	void            (*l1writewakeup) (struct PStack *);
-	void		(*l2writewakeup) (struct PStack *);
-};
-
-struct Management {
-	void            (*manl1) (struct PStack *, int, void *);
-        void            (*manl2) (struct PStack *, int, void *);
-	void            (*teil2) (struct PStack *, int, void *);
-};
-
-struct Param {
-	int             cause;
-	int             bchannel;
-	int             callref;     /* TEI-Number                      */
-	setup_parm      setup;       /* from isdnif.h numbers and Serviceindicator */
-	int             chargeinfo;  /* Charge Info - only for 1tr6 in
-				      * the moment 
-				      */
-	int		spv;	     /* SPV Flag */
-};
-
-struct PStack {
-	struct PStack  *next;
-	struct Layer1   l1;
-	struct Layer2   l2;
-	struct Layer3   l3;
-	struct Layer4   l4;
-	struct Management ma;
-	struct Param   *pa;
-	int             protocol;     /* EDSS1 or 1TR6 */
-};
-
-struct HscxState {
-	byte           *membase;
-	int             iobase;
-	int             inuse, init, active;
-	struct BufPool  sbufpool, rbufpool, smallpool;
-	struct IsdnCardState *sp;
-	int             hscx, mode;
-	int             transbufsize, receive;
-	struct BufHeader *rcvibh, *xmtibh;
-	int             rcvptr, sendptr;
-	struct PStack  *st;
-	struct tq_struct tqueue;
-	int             event;
-	struct BufQueue rq, sq;
-	int             releasebuf;
-#ifdef DEBUG_MAGIC
-	int             magic;	/* 301270 */
-#endif
-};
-
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	byte           *membase;
-	int             iobase;
-	struct BufPool  sbufpool, rbufpool, smallpool;
-	struct PStack  *stlist;
-	struct BufHeader *xmtibh, *rcvibh;
-	int             rcvptr, sendptr;
-	int             event;
-	struct tq_struct tqueue;
-	int             ph_active;
-	struct BufQueue rq, sq;
-
-	int             cardnr, ph_state;
-	struct PStack  *teistack;
-	struct HscxState hs[2];
-
-	int             dlogflag;
-	char           *dlogspace;
-	int             debug;
-	int             releasebuf;
-};
-
-struct IsdnCard {
-	byte           *membase;
-	int             interrupt;
-	unsigned int    iobase;
-	int             protocol;	/* EDSS1 or 1TR6 */
-	struct IsdnCardState *sp;
-};
-
-#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
-
-#define LAPD 0
-#define LAPB 1
-
-void            BufPoolInit(struct BufPool *bp, int order, int bpps,
-			    int maxpages);
-int             BufPoolAdd(struct BufPool *bp, int priority);
-void            BufPoolFree(struct BufPool *bp);
-int             BufPoolGet(struct BufHeader **bh,
-	      struct BufPool *bp, int priority, void *heldby, int where);
-void            BufPoolRelease(struct BufHeader *bh);
-void            BufQueueLink(struct BufQueue *bq,
-			     struct BufHeader *bh);
-int             BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
-void            BufQueueInit(struct BufQueue *bq);
-void            BufQueueRelease(struct BufQueue *bq);
-void            BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
-				int releasetoo);
-int             BufQueueLength(struct BufQueue *bq);
-void            BufQueueLinkFront(struct BufQueue *bq,
-				  struct BufHeader *bh);
-
-void            l2down(struct PStack *st,
-		       byte pr, struct BufHeader *ibh);
-void            l2up(struct PStack *st,
-		     byte pr, struct BufHeader *ibh);
-void            acceptph(struct PStack *st,
-			 struct BufHeader *ibh);
-void            setstack_isdnl2(struct PStack *st, char *debug_id);
-int             teles_inithardware(void);
-void            teles_closehardware(void);
-
-void            setstack_teles(struct PStack *st, struct IsdnCardState *sp);
-unsigned int    randomces(void);
-void            setstack_isdnl3(struct PStack *st);
-void            teles_addlist(struct IsdnCardState *sp,
-			      struct PStack *st);
-void            releasestack_isdnl2(struct PStack *st);
-void            teles_rmlist(struct IsdnCardState *sp,
-			     struct PStack *st);
-void            newcallref(struct PStack *st);
-
-int             ll_init(void);
-void            ll_stop(void), ll_unload(void);
-int             setstack_hscx(struct PStack *st, struct HscxState *hs);
-void            modehscx(struct HscxState *hs, int mode, int ichan);
-byte           *findie(byte * p, int size, byte ie, int wanted_set);
-int             getcallref(byte * p);
-
-void            FsmNew(struct Fsm *fsm,
-		       struct FsmNode *fnlist, int fncount);
-void            FsmFree(struct Fsm *fsm);
-int             FsmEvent(struct FsmInst *fi,
-			 int event, void *arg);
-void            FsmChangeState(struct FsmInst *fi,
-			       int newstate);
-void            FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int             FsmAddTimer(struct FsmTimer *ft,
-			  int millisec, int event, void *arg, int where);
-void            FsmDelTimer(struct FsmTimer *ft, int where);
-int             FsmTimerRunning(struct FsmTimer *ft);
-void            jiftime(char *s, long mark);
-
-void            CallcNew(void);
-void            CallcFree(void);
-int             CallcNewChan(void);
-void            CallcFreeChan(void);
-int             teles_command(isdn_ctrl * ic);
-int             teles_writebuf(int id, int chan, const u_char * buf, int count, int user);
-void            teles_putstatus(char *buf);
-void            teles_reportcard(int cardnr);
-int             ListLength(struct BufHeader *ibh);
-void            dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
-void            iecpy(byte * dest, byte * iestart, int ieoffset);
-void            setstack_transl2(struct PStack *st);
-void            releasestack_transl2(struct PStack *st);
-void            close_hscxstate(struct HscxState *);
-void            setstack_tei(struct PStack *st);
-
-struct LcFsm {
-	struct FsmInst  lcfi;
-	int             type;
-	struct Channel *ch;
-	void            (*lccall) (struct LcFsm *, int, void *);
-	struct PStack  *st;
-	int             l2_establish;
-	int             l2_start;
-	struct FsmTimer act_timer;
-	char            debug_id[32];
-};
-
-struct Channel {
-	struct PStack   ds, is;
-	struct IsdnCardState *sp;
-	int             hscx;
-	int             chan;
-	int             incoming;
-	struct FsmInst  fi;
-	struct LcFsm    lc_d, lc_b;
-	struct Param    para;
-	int             debug;
-#ifdef DEBUG_MAGIC
-	int             magic;	/* 301272 */
-#endif
-	int             l2_protocol, l2_active_protocol;
-	int             l2_primitive, l2_headersize;
-	int             data_open;
-	int             outcallref;
-	int             impair;
-};
-
-#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
-  sizeof(void *))/bpps)
-#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
-  sizeof(struct BufHeader))
-
-#endif
-
-void            Isdnl2New(void);
-void            Isdnl2Free(void);
-void            TeiNew(void);
-void            TeiFree(void);
-
-
-
-
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.1.36/linux/drivers/net/3c501.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c501.c	Mon May 12 10:35:40 1997
@@ -413,7 +413,7 @@
 	 *	Avoid timer-based retransmission conflicts.
 	 */
 
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 	{
 		restore_flags(flags);
 		printk("%s: Transmitter access conflict.\n", dev->name);
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.1.36/linux/drivers/net/3c505.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c505.c	Mon May 12 10:35:40 1997
@@ -412,7 +412,7 @@
 		return FALSE;
 
 	/* Avoid contention */
-	if (set_bit(1, &adapter->send_pcb_semaphore)) {
+	if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
 		if (elp_debug >= 3) {
 			printk("%s: send_pcb entered while threaded\n", dev->name);
 		}
@@ -545,7 +545,7 @@
 	}
 
 	if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
-		if (set_bit(0, (void *) &adapter->busy)) {
+		if (test_and_set_bit(0, (void *) &adapter->busy)) {
 			if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
 				set_hsf(dev, HSF_PCB_NAK);
 				printk("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
@@ -621,7 +621,7 @@
 	}
 
 	/* if this happens, we die */
-	if (set_bit(0, (void *) &adapter->dmaing))
+	if (test_and_set_bit(0, (void *) &adapter->dmaing))
 		printk("%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);
 
 	skb->dev = dev;
@@ -1031,7 +1031,7 @@
 	 */
 	unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
 
-	if (set_bit(0, (void *) &adapter->busy)) {
+	if (test_and_set_bit(0, (void *) &adapter->busy)) {
 		if (elp_debug >= 2)
 			printk("%s: transmit blocked\n", dev->name);
 		return FALSE;
@@ -1054,7 +1054,7 @@
 		return FALSE;
 	}
 	/* if this happens, we die */
-	if (set_bit(0, (void *) &adapter->dmaing))
+	if (test_and_set_bit(0, (void *) &adapter->dmaing))
 		printk("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
 
 	adapter->current_dma.direction = 1;
@@ -1119,7 +1119,7 @@
 	if (elp_debug >= 3)
 		printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
 
-	if (set_bit(0, (void *) &dev->tbusy)) {
+	if (test_and_set_bit(0, (void *) &dev->tbusy)) {
 		printk("%s: transmitter access conflict\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.1.36/linux/drivers/net/3c507.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c507.c	Mon May 12 10:35:40 1997
@@ -479,7 +479,7 @@
 	}
 
 	/* Block a timer-based transmit from overlapping. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else
 	{
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.36/linux/drivers/net/3c509.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c509.c	Mon May 12 10:35:40 1997
@@ -468,7 +468,7 @@
 #endif
 #endif
 	/* Avoid timer-based retransmission conflicts. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		lp->stats.tx_bytes+=skb->len;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.1.36/linux/drivers/net/3c523.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c523.c	Mon May 12 10:35:40 1997
@@ -1137,7 +1137,7 @@
     return 0;
   }
 
-  if (set_bit(0, (void*)&dev->tbusy) != 0) {
+  if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
      printk("%s: Transmitter access conflict.\n", dev->name);
   } else {
     memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.1.36/linux/drivers/net/3c59x.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/3c59x.c	Mon May 12 10:35:40 1997
@@ -799,7 +799,7 @@
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	   If this ever occurs the queue layer is doing something evil! */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.1.36/linux/drivers/net/a2065.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/a2065.c	Mon May 12 10:35:40 1997
@@ -599,7 +599,7 @@
 #ifdef OLD_METHOD
 	dev->tbusy = 1;
 #else
-	if (set_bit (0, (void *) &dev->tbusy) != 0) {
+	if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
 		printk ("Transmitter access conflict.\n");
 		return -1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v2.1.36/linux/drivers/net/apricot.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/apricot.c	Mon May 12 10:35:40 1997
@@ -616,7 +616,7 @@
 
     /* Block a timer-based transmit from overlapping.  This could better be
        done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-    if (set_bit(0, (void*)&dev->tbusy) != 0)
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 	printk("%s: Transmitter access conflict.\n", dev->name);
     else
     {
diff -u --recursive --new-file v2.1.36/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.1.36/linux/drivers/net/arcnet.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/arcnet.c	Mon May 12 10:35:40 1997
@@ -1588,7 +1588,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-        if (set_bit(0, (void*)&dev->tbusy) != 0)
+        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
         {
             BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
             		ARCSTATUS,lp->intx,jiffies-dev->trans_start);
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.1.36/linux/drivers/net/ariadne.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/ariadne.c	Mon May 12 10:35:40 1997
@@ -593,12 +593,12 @@
 
     /* Block a timer-based transmit from overlapping.  This could better be
 	done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-    if (set_bit(0, (void*)&dev->tbusy) != 0) {
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 	printk("%s: Transmitter access conflict.\n", dev->name);
 	return(1);
     }
 
-    if (set_bit(0, (void*)&priv->lock) != 0) {
+    if (test_and_set_bit(0, (void*)&priv->lock) != 0) {
 	if (ariadne_debug > 0)
 	    printk("%s: tx queue lock!.\n", dev->name);
 	/* don't clear dev->tbusy flag. */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.1.36/linux/drivers/net/at1700.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/at1700.c	Mon May 12 10:35:40 1997
@@ -395,7 +395,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v2.1.36/linux/drivers/net/atarilance.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/atarilance.c	Mon May 12 10:35:40 1997
@@ -776,12 +776,12 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit( 0, (void*)&dev->tbusy ) != 0) {
+	if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
 		DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
 		return 1;
 	}
 
-	if (set_bit( 0, (void*)&lp->lock ) != 0) {
+	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
 		DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
 		/* don't clear dev->tbusy flag. */
 		return 1;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.1.36/linux/drivers/net/atp.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/atp.c	Mon May 12 10:35:40 1997
@@ -437,7 +437,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.1.36/linux/drivers/net/cs89x0.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/cs89x0.c	Mon May 12 10:35:40 1997
@@ -752,7 +752,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		struct net_local *lp = (struct net_local *)dev->priv;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.1.36/linux/drivers/net/de4x5.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/de4x5.c	Mon May 12 10:35:41 1997
@@ -3,8 +3,30 @@
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
-    This software may be used and distributed according to the terms of
-    the GNU Public License, incorporated herein by reference.
+    Testing resources for this driver have been made available
+    in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
+
+    The author may be reached at davies@maniac.ultranet.com.
+
+    This program is free software; you can redistribute  it and/or modify it
+    under  the terms of  the GNU General  Public License as published by the
+    Free Software Foundation;  either version 2 of the  License, or (at your
+    option) any later version.
+
+    THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+    WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+    NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+    USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+    ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You should have received a copy of the  GNU General Public License along
+    with this program; if not, write  to the Free Software Foundation, Inc.,
+    675 Mass Ave, Cambridge, MA 02139, USA.
 
     Originally,   this  driver  was    written  for the  Digital   Equipment
     Corporation series of EtherWORKS ethernet cards:
@@ -15,8 +37,8 @@
 	DE450 TP/COAX/AUI PCI
 	DE500 10/100 PCI Fasternet
 
-    but it  will now  attempt  to support all  cards   which conform  to the
-    Digital  Semiconductor SROM    Specification.   The   driver   currently
+    but it  will  now attempt  to  support all  cards which   conform to the
+    Digital Semiconductor   SROM   Specification.    The  driver   currently
     recognises the following chips:
 
         DC21040     (no SROM)
@@ -32,6 +54,7 @@
 	SMC8432
 	SMC9332 (w/new SROM)
 	ZNYX31[45]
+	ZNYX346 10/100 4 port (can act as a 10/100 bridge!) 
 
     The driver has been tested on a relatively busy network using the DE425,
     DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
@@ -48,13 +71,11 @@
     measurement. Their error is +/-20k on a quiet (private) network and also
     depend on what load the CPU has.
 
-    The author may be reached at davies@maniac.ultranet.com.
-
     =========================================================================
-    This driver  has been written substantially  from scratch,  although its
+    This driver  has been written substantially  from  scratch, although its
     inheritance of style and stack interface from 'ewrk3.c' and in turn from
     Donald Becker's 'lance.c' should be obvious. With the module autoload of
-    every  usable DECchip board,  I pinched Donald's  'next_module' field to
+    every  usable DECchip board,  I  pinched Donald's 'next_module' field to
     link my modules together.
 
     Upto 15 EISA cards can be supported under this driver, limited primarily
@@ -80,7 +101,7 @@
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
     2) for fixed  autoprobes (not  recommended),  edit the source code  near
-    line 4927 to reflect the I/O address  you're using, or assign these when
+    line 5005 to reflect the I/O address  you're using, or assign these when
     loading by:
 
                    insmod de4x5 io=0xghh           where g = bus number
@@ -113,7 +134,7 @@
     By  default,  the driver will  now   autodetect any  DECchip based card.
     Should you have a need to restrict the driver to DIGITAL only cards, you
     can compile with a  DEC_ONLY define, or if  loading as a module, use the
-    'dec_only=1'  parameter.
+    'dec_only=1'  parameter. 
 
     I've changed the timing routines to  use the kernel timer and scheduling
     functions  so that the  hangs  and other assorted problems that occurred
@@ -145,6 +166,19 @@
     (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
     wired IRQs.
 
+    I have added a temporary fix for interrupt problems when some SCSI cards
+    share the same interrupt as the DECchip based  cards. The problem occurs
+    because  the SCSI card wants to  grab the interrupt  as a fast interrupt
+    (runs the   service routine with interrupts turned   off) vs.  this card
+    which really needs to run the service routine with interrupts turned on.
+    This driver will  now   add the interrupt service   routine  as  a  fast
+    interrupt if it   is bounced from the   slow interrupt.  THIS IS NOT   A
+    RECOMMENDED WAY TO RUN THE DRIVER  and has been done  for a limited time
+    until  people   sort  out their  compatibility    issues and the  kernel
+    interrupt  service code  is  fixed.   YOU  SHOULD SEPARATE OUT  THE FAST
+    INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+    run on the same interrupt. PCMCIA/CardBus is another can of worms...
+
     TO DO:
     ------
 
@@ -234,7 +268,7 @@
       0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
                            by <bhat@mundook.cs.mu.OZ.AU>
       0.45    8-Dec-96    Include endian functions for PPC use, from work 
-                           by <cort@cs.nmt.edu>.
+                           by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
       0.451  28-Dec-96    Added fix to allow autoprobe for modules after
                            suggestion from <mjacob@feral.com>.
       0.5    30-Jan-97    Added SROM decoding functions.
@@ -247,11 +281,30 @@
 			  Added attempt to use an SMC9332 with broken SROM.
 			  Added fix for ZYNX multi-mac cards that didn't
 			   get their IRQs wired correctly.
+      0.51   13-Feb-97    Added endian fixes for the SROM accesses from
+			   <paubert@iram.es>
+			  Fix init_connection() to remove extra device reset.
+			  Fix MAC/PHY reset ordering in dc21140m_autoconf().
+			  Fix initialisation problem with lp->timeout in
+			   typeX_infoblock() from <paubert@iram.es>.
+			  Fix MII PHY reset problem from work done by
+			   <paubert@iram.es>.
+      0.52   26-Apr-97    Some changes may not credit the right people -
+                           a disk crash meant I lost some mail.
+			  Change RX interrupt routine to drop rather than 
+			   defer packets to avoid hang reported by 
+			   <g.thomas@opengroup.org>.
+			  Fix srom_exec() to return for COMPACT and type 1
+			   infoblocks.
+			  Added DC21142 and DC21143 functions.
+			  Added byte counters from <phil@tazenda.demon.co.uk>
+			  Added SA_INTERRUPT temporary fix from 
+			   <mjacob@feral.com>.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -270,8 +323,8 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/uaccess.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -286,14 +339,37 @@
 
 #define c_char const char
 
+#include <linux/version.h>
+#if	LINUX_VERSION_CODE < ((2 << 16) | (1 << 8))
+#define        net_device_stats      enet_statistics
+#define copy_to_user(a,b,c)   memcpy_tofs(a,b,c)
+#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
+#define le16_to_cpu(a) cpu_to_le16(a) 
+#define le32_to_cpu(a) cpu_to_le32(a) 
+#ifdef __powerpc__
+#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
+#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
+		        (((a) & 0x0000ff00U) <<  8) |\
+		        (((a) & 0x00ff0000U) >>  8) |\
+		        (((a) & 0xff000000U) >> 24))
+#else
+#define cpu_to_le16(a) (a)
+#define cpu_to_le32(a) (a)
+#endif  /* __powerpc__ */
+#include	<asm/segment.h>
+#else
+#include	<asm/uaccess.h>
+#endif  /* LINUX_VERSION_CODE */
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+
 /*
 ** MII Information
 */
 struct phy_table {
-    int reset;              /* Hard reset required? */
-    int id;                 /* IEEE OUI */
+    int reset;              /* Hard reset required?                         */
+    int id;                 /* IEEE OUI                                     */
     int ta;                 /* One cycle TA time - 802.3u is confusing here */
-    struct {                /* Non autonegotiation (parallel) speed det. */
+    struct {                /* Non autonegotiation (parallel) speed det.    */
 	int reg;
 	int mask;
 	int value;
@@ -301,25 +377,35 @@
 };
 
 struct mii_phy {
-    int reset;              /* Hard reset required? */
-    int id;                 /* IEEE OUI */
-    int ta;                 /* One cycle TA time */
+    int reset;              /* Hard reset required?                      */
+    int id;                 /* IEEE OUI                                  */
+    int ta;                 /* One cycle TA time                         */
     struct {                /* Non autonegotiation (parallel) speed det. */
 	int reg;
 	int mask;
 	int value;
     } spd;
-    int addr;               /* MII address for the PHY */
-    u_char  *gep;           /* Start of GEP sequence block in SROM */
-    u_char  *rst;           /* Start of reset sequence in SROM */
-    u_int mc;               /* Media Capabilities */
-    u_int ana;              /* NWay Advertisement */
-    u_int fdx;              /* Full DupleX capabilites for each media */
-    u_int ttm;              /* Transmit Threshold Mode for each media */
+    int addr;               /* MII address for the PHY                   */
+    u_char  *gep;           /* Start of GEP sequence block in SROM       */
+    u_char  *rst;           /* Start of reset sequence in SROM           */
+    u_int mc;               /* Media Capabilities                        */
+    u_int ana;              /* NWay Advertisement                        */
+    u_int fdx;              /* Full DupleX capabilites for each media    */
+    u_int ttm;              /* Transmit Threshold Mode for each media    */
 };
 
 #define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
 
+struct sia_phy {
+    u_char mc;              /* Media Code                                */
+    u_char ext;             /* csr13-15 valid when set                   */
+    int csr13;              /* SIA Connectivity Register                 */
+    int csr14;              /* SIA TX/RX Register                        */
+    int csr15;              /* SIA General Register                      */
+    int gepc;               /* SIA GEP Control Information               */
+    int gep;                /* SIA GEP Data                              */
+};
+
 /*
 ** Define the know universe of PHY devices that can be
 ** recognised by this driver
@@ -327,8 +413,8 @@
 static struct phy_table phy_info[] = {
     {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},   /* National TX */
     {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},   /* Broadcom T4 */
-    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},   /* SEEQ T4 */
-    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}    /* Cypress T4 */
+    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},   /* SEEQ T4     */
+    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}    /* Cypress T4  */
 };
 
 /*
@@ -354,7 +440,6 @@
      0x00,0x18,}
 };
 
-#undef DE4X5_VERBOSE     /* define to get more verbose startup messages */
 
 #ifdef DE4X5_DEBUG
 static int de4x5_debug = DE4X5_DEBUG;
@@ -581,6 +666,7 @@
     int  setup_f;                           /* Setup frame filtering type   */
     int  local_state;                       /* State within a 'media' state */
     struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
+    struct sia_phy sia;                     /* SIA PHY Information          */
     int  active;                            /* Index to active PHY device   */
     int  mii_cnt;                           /* Number of attached PHY's     */
     int  timeout;                           /* Scheduling counter           */
@@ -770,9 +856,6 @@
 static void    yawn(struct device *dev, int state);
 static int     de4x5_dev_index(char *s);
 static void    link_modules(struct device *dev, struct device *tmp);
-#ifdef MODULE
-static struct  device *unlink_modules(struct device *p);
-#endif
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
@@ -794,6 +877,7 @@
 #ifdef MODULE
 int  init_module(void);
 void cleanup_module(void);
+static struct  device *unlink_modules(struct device *p);
 static int autoprobed = 0, loading_module = 1;
 # else
 static int autoprobed = 0, loading_module = 0;
@@ -898,7 +982,7 @@
 				  PCI_CFDA_PSM, WAKEUP);
     }
     de4x5_ms_delay(10);
-    
+
     RESET_DE4X5;
     
     if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
@@ -964,6 +1048,9 @@
 	lp->chipset = bus.chipset;
 	lp->cache.priv = tmp;
 	lp->cache.gepc = GEP_INIT;
+	lp->asBit = GEP_SLNK;
+	lp->asPolarity = GEP_SLNK;
+	lp->asBitValid = TRUE;
 	lp->timeout = -1;
 	lp->useSROM = useSROM;
 	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
@@ -1071,11 +1158,6 @@
 	
 	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
 	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-
-#ifdef DE4X5_VERBOSE
-	printk("%s: INFOLEAF_SIZE: %ld, COMPACT: %ld\n", dev->name, 
-	       INFOLEAF_SIZE, COMPACT);
-#endif
     }
     
     if (de4x5_debug & DEBUG_VERSION) {
@@ -1133,18 +1215,29 @@
     
     if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
 		                                     lp->adapter_name, dev)) {
-	printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
-	status = -EAGAIN;
-    } else {
-	dev->tbusy = 0;                         
-	dev->start = 1;
-	dev->interrupt = UNMASK_INTERRUPTS;
-	dev->trans_start = jiffies;
-	
-	START_DE4X5;
-	
-	de4x5_setup_intr(dev);
+	printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+	if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+			                             lp->adapter_name, dev)) {
+	    printk("\n              Cannot get IRQ- reconfigure your hardware.\n");
+	    disable_ast(dev);
+	    de4x5_free_rx_buffs(dev);
+	    de4x5_free_tx_buffs(dev);
+	    yawn(dev, SLEEP);
+	    lp->state = CLOSED;
+	    return -EAGAIN;
+	} else {
+	    printk("\n              Succeeded, but you should reconfigure your hardware to avoid this.\n");
+	    printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
+	}
     }
+    dev->tbusy = 0;                         
+    dev->start = 1;
+    dev->interrupt = UNMASK_INTERRUPTS;
+    dev->trans_start = jiffies;
+    
+    START_DE4X5;
+	
+    de4x5_setup_intr(dev);
     
     if (de4x5_debug & DEBUG_OPEN) {
 	printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
@@ -1287,7 +1380,7 @@
     sti();
 
     /* Test if cache is already locked - requeue skb if so */
-    if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
 
     /* Transmit descriptor ring full or stale skb */
     if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
@@ -1300,9 +1393,6 @@
 	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
 	}
     } else if (skb->len > 0) {
-	/* Update the byte counter */
-	lp->stats.tx_bytes += skb->len;
-
 	/* If we already have stuff queued locally, use that first */
 	if (lp->cache.skb && !dev->interrupt) {
 	    de4x5_put_cache(dev, skb);
@@ -1313,6 +1403,9 @@
 	    cli();
 	    set_bit(0, (void*)&dev->tbusy);
 	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+#if	LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ 	    lp->stats.tx_bytes += skb->len;
+#endif
 	    outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
 		
 	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -1326,7 +1419,7 @@
 	}
 	if (skb) de4x5_putb_cache(dev, skb);
     }
-
+    
     lp->cache.lock = 0;
 
     return status;
@@ -1360,9 +1453,11 @@
 	
     if (dev->interrupt)
       printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
+	
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
+#if	LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
     synchronize_irq();
+#endif
     dev->interrupt = MASK_INTERRUPTS;
 	
     for (limit=0; limit<8; limit++) {
@@ -1394,8 +1489,8 @@
     }
 
     /* Load the TX ring with any locally stored packets */
-    if (!set_bit(0, (void *)&lp->cache.lock)) {
-	if (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
+    if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
+	while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
 	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
 	}
 	lp->cache.lock = 0;
@@ -1450,19 +1545,21 @@
 		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
 		    printk("%s: Insufficient memory; nuking packet.\n", 
 			                                            dev->name);
-		    lp->stats.rx_dropped++;   /* Really, deferred. */
-		    break;
-		}
-		de4x5_dbg_rx(skb, pkt_len);
+		    lp->stats.rx_dropped++;
+		} else {
+		    de4x5_dbg_rx(skb, pkt_len);
 
-		/* Push up the protocol stack */
-		skb->protocol=eth_type_trans(skb,dev);
-		netif_rx(skb);
+		    /* Push up the protocol stack */
+		    skb->protocol=eth_type_trans(skb,dev);
+		    netif_rx(skb);
 		    
-		/* Update stats */
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += pkt_len;
-		de4x5_local_stats(dev, skb->data, pkt_len);
+		    /* Update stats */
+		    lp->stats.rx_packets++;
+#if	LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
+ 		    lp->stats.rx_bytes += pkt_len;
+#endif
+		    de4x5_local_stats(dev, skb->data, pkt_len);
+		}
 	    }
 	    
 	    /* Change buffer ownership for this frame, back to the adapter */
@@ -1575,10 +1672,7 @@
 	if ((omr & OMR_TR) < OMR_TR) {
 	    omr += 0x4000;
 	} else {
-	    if (omr & OMR_TTM)
-		omr &= ~OMR_TTM;
-	    else
-		omr |= OMR_SF;
+	    omr |= OMR_SF;
 	}
 	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
     }
@@ -1645,7 +1739,8 @@
     return 0;
 }
 
-static struct net_device_stats *de4x5_get_stats(struct device *dev)
+static struct net_device_stats *
+de4x5_get_stats(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1880,7 +1975,7 @@
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
-    u_short vendor, index, status;
+    u_short dev_id, vendor, index, status;
     u_int class = DE4X5_CLASS_CODE;
     u_int device, iobase;
     struct bus_type *lp = &bus;
@@ -1908,7 +2003,8 @@
 	if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
 	    device = 0;
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
-	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device);
+	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+	    device = dev_id;
 	    device <<= 8;
 	    if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
 		continue;
@@ -2091,31 +2187,6 @@
     return;
 }
 
-#ifdef MODULE
-static struct device *
-unlink_modules(struct device *p)
-{
-    struct device *next = NULL;
-
-    if (p->priv) {                          /* Private areas allocated?  */
-	struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-
-	next = lp->next_module;
-	if (lp->cache.buf) {                /* MAC buffers allocated?    */
-	    kfree(lp->cache.buf);           /* Free the MAC buffers      */
-	}
-	kfree(lp->cache.priv);              /* Free the private area     */
-	release_region(p->base_addr, (lp->bus == PCI ? 
-				      DE4X5_PCI_TOTAL_SIZE :
-				      DE4X5_EISA_TOTAL_SIZE));
-    }
-    unregister_netdev(p);
-    kfree(p);                               /* Free the device structure */
-    
-    return next;
-}
-#endif
-
 /*
 ** Auto configure the media here rather than setting the port at compile
 ** time. This routine is called by de4x5_init() and when a loss of media is
@@ -2300,6 +2371,7 @@
 	    lp->media = prev_state;
 	} else {
 	    lp->media = INIT;
+	    lp->tcount++;
 	}
     }
 
@@ -2527,16 +2599,22 @@
 
     switch(lp->media) {
       case INIT: 
-	DISABLE_IRQs;
-	lp->tx_enable = FALSE;
-        lp->linkOK = 0;
-/*	lp->timeout = -1;*/
+        if (lp->timeout < 0) {
+	    DISABLE_IRQs;
+	    lp->tx_enable = FALSE;
+	    lp->linkOK = 0;
+	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+	}
 	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
 	    next_tick &= ~TIMER_CB;
 	} else {
-	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
 	    if (lp->useSROM) {
 		srom_map_media(dev);
+		srom_exec(dev, lp->phy[lp->active].gep);
+		if (lp->infoblock_media == ANS) {
+		    ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		}
 	    } else {
 		lp->tmp = MII_SR_ASSC;     /* Fake out the MII speed set */
 		SET_10Mb;
@@ -2752,9 +2830,9 @@
         de4x5_dbg_media(dev);
 	lp->c_media = lp->media;          /* Stop scrolling media messages */
     }
-    de4x5_restore_skbs(dev);
+
     cli();
-    de4x5_rx(dev);
+    de4x5_restore_skbs(dev);
     de4x5_setup_intr(dev);
     lp->tx_enable = YES;
     dev->tbusy = 0;
@@ -2766,7 +2844,9 @@
 }
 
 /*
-** General PHY reset function.
+** General PHY reset function. Some MII devices don't reset correctly
+** since their MII address pins can float at voltages that are dependent
+** on the signal pin use. Do a double reset to ensure a reset.
 */
 static int
 de4x5_reset_phy(struct device *dev)
@@ -2780,8 +2860,10 @@
 	    if (lp->useSROM) {
 		if (lp->phy[lp->active].rst) { /* MII device specific reset */
 		    srom_exec(dev, lp->phy[lp->active].rst);
+		    srom_exec(dev, lp->phy[lp->active].rst);
 		} else if (lp->rst) {          /* Type 5 infoblock reset */
 		    srom_exec(dev, lp->rst);
+		    srom_exec(dev, lp->rst);
 		}
 	    } else {
 		PHY_HARD_RESET;
@@ -3151,13 +3233,26 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
+    int i;
     s32 omr;
 
     if (lp->cache.save_cnt) {
 	STOP_DE4X5;
-	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
-	de4x5_sw_reset(dev);
-	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
+	outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+	outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+    
+	lp->rx_new = lp->rx_old = 0;
+	lp->tx_new = lp->tx_old = 0;
+    
+	for (i = 0; i < lp->rxRingSize; i++) {
+	    lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+	}
+    
+	for (i = 0; i < lp->txRingSize; i++) {
+	    lp->tx_ring[i].status = cpu_to_le32(0);
+	}
+    
+	barrier();
 	lp->cache.save_cnt--;
 	START_DE4X5;
     }
@@ -3446,9 +3541,10 @@
     if (lp->chipset == DC21040) {
 	outl(0, aprom_addr);           /* Reset Ethernet Address ROM Pointer */
     } else {                           /* Read new srom */
-	short *p = (short *)&lp->srom;
+	u_short tmp, *p = (short *)&lp->srom;
 	for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
-	    *p++ = srom_rd(aprom_addr, i);
+	    tmp = srom_rd(aprom_addr, i);
+	    *p++ = le16_to_cpu(tmp);
 	}
 	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
@@ -3756,7 +3852,7 @@
 	}
     }
 
-    lp->infoleaf_offset = (u_short)*((u_short *)(p+1));
+    lp->infoleaf_offset = TWIDDLE(p+1);
 
     return 0;
 }
@@ -3776,14 +3872,10 @@
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     u_char count;
 
+    p+=2;
     if (lp->chipset == DC21140) {
-	p+=2;
 	lp->cache.gepc = (*p++ | GEP_CTRL);
 	outl(lp->cache.gepc, DE4X5_GEP);
-    } else if (lp->chipset == DC21142) {
-	p+=2;
-    } else if (lp->chipset == DC21143) {
-	p+=2;
     }
 
     /* Block count */
@@ -3815,7 +3907,7 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    u_char count = *p++;
+    u_char count = (p ? *p++ : 0);
 
     while (count--) {
 	if (lp->chipset == DC21140) {
@@ -3910,7 +4002,7 @@
 	}
     }
 
-    if (lp->media == INIT) {
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
         outl(lp->cache.gepc, DE4X5_GEP);
 	lp->infoblock_media = (*p++) & COMPACT_MC;
 	lp->cache.gep = *p++;
@@ -3949,7 +4041,7 @@
 	}
     }
 
-    if (lp->media == INIT) {
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
         outl(lp->cache.gepc, DE4X5_GEP);
 	p+=2;
 	lp->infoblock_media = (*p++) & BLOCK0_MC;
@@ -3976,9 +4068,7 @@
 type1_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char len = (*p & BLOCK_LEN)+1;
-    int ana;
 
     /* Recursively figure out the info blocks */
     if (--count > lp->tcount) {
@@ -3989,22 +4079,20 @@
 	}
     }
 
+    p += 2;
     if (lp->state == INITIALISED) {
-	lp->ibn = 1; p += 2;
+	lp->ibn = 1;
 	lp->active = *p++;
 	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
 	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
-	lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
-	lp->phy[lp->active].ana = *(u_short *)p; p += 2;
-	lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
-	lp->phy[lp->active].ttm = *(u_short *)p;
+	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ttm = TWIDDLE(p);
 	return 0;
-    } else if (lp->media == INIT) {
-	if (lp->phy[lp->active].gep) {
-	    srom_exec(dev, lp->phy[lp->active].gep);
-	}
-        ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
-	mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 1;
+        lp->active = *p;
 	lp->infoblock_csr6 = OMR_PS | OMR_HBD;
 	lp->useMII = TRUE;
 	lp->infoblock_media = ANS;
@@ -4040,10 +4128,10 @@
         lp->active = *p++;
 	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
 	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
-	lp->phy[lp->active].mc  = *(u_short *)p; p += 2;
-	lp->phy[lp->active].ana = *(u_short *)p; p += 2;
-	lp->phy[lp->active].fdx = *(u_short *)p; p += 2;
-	lp->phy[lp->active].ttm = *(u_short *)p;
+	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ttm = TWIDDLE(p);
 	return 0;
     } else if (lp->media == INIT) {
 	p+=2;
@@ -4672,18 +4760,12 @@
     u_long iobase = dev->base_addr;
     int i, j, status = 0;
     s32 omr;
-    struct {
-	u8  *addr;
-	u16 *sval;
-	u32 *lval;
+    union {
+	u8  addr[144];
+	u16 sval[72];
+	u32 lval[36];
     } tmp;
-
-    tmp.addr = tmp.sval = tmp.lval = kmalloc(HASH_TABLE_LEN * ETH_ALEN, GFP_KERNEL);
-    if (!tmp.addr){ 
-      printk("%s ioctl: memory squeeze.\n", dev->name);
-      return -ENOMEM;
-    }
-
+    
     switch(ioc->cmd) {
       case DE4X5_GET_HWADDR:           /* Get the hardware address */
 	ioc->len = ETH_ALEN;
@@ -4710,7 +4792,7 @@
 	}
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
-	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+	while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
 	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -4743,39 +4825,12 @@
 	
 	break;
       case DE4X5_GET_MCA:              /* Get the multicast address table */
-	ioc->len = (HASH_TABLE_LEN >> 3);
-	status = verify_area(VERIFY_WRITE, ioc->data, ioc->len);
-	if (!status) {
-	    copy_to_user(ioc->data, lp->setup_frame, ioc->len); 
-	}
-	
 	break;
       case DE4X5_SET_MCA:              /* Set a multicast address */
-	if (suser()) {
-	    /******* FIX ME! ********/
-	    if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
-		if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) {
-		    copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
-		    set_multicast_list(dev);
-		}
-	    } else {
-		set_multicast_list(dev);
-	    }
-	} else {
-	    status = -EPERM;
-	}
-	
 	break;
       case DE4X5_CLR_MCA:              /* Clear all multicast addresses */
-	if (suser()) {
-	    /******* FIX ME! ********/
-	    set_multicast_list(dev);
-	} else {
-	    status = -EPERM;
-	}
-	
 	break;
-      case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
+      case DE4X5_MCA_EN:               /* Enable pass all multicast addresses*/
 	if (suser()) {
 	    omr = inl(DE4X5_OMR);
 	    omr |= OMR_PM;
@@ -4840,7 +4895,8 @@
 	}
 	break;
 	
-#define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
+/*
+#define DE4X5_DUMP              0x0f / * Dump the DE4X5 Status * /
 	
       case DE4X5_DUMP:
 	j = 0;
@@ -4931,12 +4987,11 @@
 	}
 	
 	break;
+*/
       default:
 	status = -EOPNOTSUPP;
     }
-
-    kfree(tmp.addr);
-
+    
     return status;
 }
 
@@ -4975,6 +5030,30 @@
 
     return;
 }
+
+static struct device *
+unlink_modules(struct device *p)
+{
+    struct device *next = NULL;
+
+    if (p->priv) {                          /* Private areas allocated?  */
+	struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+	next = lp->next_module;
+	if (lp->cache.buf) {                /* MAC buffers allocated?    */
+	    kfree(lp->cache.buf);           /* Free the MAC buffers      */
+	}
+	kfree(lp->cache.priv);              /* Free the private area     */
+	release_region(p->base_addr, (lp->bus == PCI ? 
+				      DE4X5_PCI_TOTAL_SIZE :
+				      DE4X5_EISA_TOTAL_SIZE));
+    }
+    unregister_netdev(p);
+    kfree(p);                               /* Free the device structure */
+    
+    return next;
+}
+
 #endif /* MODULE */
 
 
diff -u --recursive --new-file v2.1.36/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.1.36/linux/drivers/net/de4x5.h	Sun Feb  2 05:02:05 1997
+++ linux/drivers/net/de4x5.h	Mon May 12 10:35:41 1997
@@ -139,7 +139,7 @@
 #define CFCS_DST    0x06000000       /* DEVSEL Timing         (S) */
 #define CFCS_DPR    0x01000000       /* Data Parity Report    (S) */
 #define CFCS_FBB    0x00800000       /* Fast Back-To-Back     (S) */
-#define CFCS_SLE    0x00000100       /* System Error Enable   (C) */
+#define CFCS_SEE    0x00000100       /* System Error Enable   (C) */
 #define CFCS_PER    0x00000040       /* Parity Error Response (C) */
 #define CFCS_MO     0x00000004       /* Master Operation      (C) */
 #define CFCS_MSA    0x00000002       /* Memory Space Access   (C) */
@@ -150,8 +150,8 @@
 */
 #define CFRV_BC     0xff000000       /* Base Class */
 #define CFRV_SC     0x00ff0000       /* Subclass */
-#define CFRV_SN     0x000000f0       /* Step Number */
-#define CFRV_RN     0x0000000f       /* Revision Number */
+#define CFRV_RN     0x000000f0       /* Revision Number */
+#define CFRV_SN     0x0000000f       /* Step Number */
 #define BASE_CLASS  0x02000000       /* Indicates Network Controller */
 #define SUB_CLASS   0x00000000       /* Indicates Ethernet Controller */
 #define STEP_NUMBER 0x00000020       /* Increments for future chips */
@@ -170,12 +170,33 @@
 #define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
 
 /*
+** PCI Configuration Card Information Structure Register (PCI_CCIS)
+*/
+#define CCIS_ROMI   0xf0000000       /* ROM Image */
+#define CCIS_ASO    0x0ffffff8       /* Address Space Offset */
+#define CCIS_ASI    0x00000007       /* Address Space Indicator */
+
+/*
+** PCI Configuration Subsystem ID Register (PCI_SSID)
+*/
+#define SSID_SSID   0xffff0000       /* Subsystem ID */
+#define SSID_SVID   0x0000ffff       /* Subsystem Vendor ID */
+
+/*
 ** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
 */
 #define CBER_MASK   0xfffffc00       /* Expansion ROM Base Address Mask */
 #define CBER_ROME   0x00000001       /* ROM Enable */
 
 /*
+** PCI Configuration Interrupt Register (PCI_CFIT)
+*/
+#define CFIT_MXLT   0xff000000       /* MAX_LAT Value (0.25us periods) */
+#define CFIT_MNGT   0x00ff0000       /* MIN_GNT Value (0.25us periods) */
+#define CFIT_IRQP   0x0000ff00       /* Interrupt Pin */
+#define CFIT_IRQL   0x000000ff       /* Interrupt Line */
+
+/*
 ** PCI Configuration Power Management Area Register (PCI_CFPM)
 */
 #define SLEEP       0x80             /* Power Saving Sleep Mode */
@@ -188,6 +209,7 @@
 /*
 ** DC21040 Bus Mode Register (DE4X5_BMR)
 */
+#define BMR_RML    0x00200000       /* [Memory] Read Multiple */
 #define BMR_DBO    0x00100000       /* Descriptor Byte Ordering (Endian) */
 #define BMR_TAP    0x000e0000       /* Transmit Automatic Polling */
 #define BMR_DAS    0x00010000       /* Diagnostic Address Space */
@@ -198,6 +220,7 @@
 #define BMR_BAR    0x00000002       /* Bus ARbitration */
 #define BMR_SWR    0x00000001       /* Software Reset */
 
+                                    /* Timings here are for 10BASE-T/AUI only*/
 #define TAP_NOPOLL 0x00000000       /* No automatic polling */
 #define TAP_200US  0x00020000       /* TX automatic polling every 200us */
 #define TAP_800US  0x00040000       /* TX automatic polling every 800us */
@@ -249,18 +272,21 @@
 #define TRBA       0xfffffffc       /* TX Descriptor List Start Address */
 
 /*
-** DC21040 Status Register (DE4X5_STS)
+** Status Register (DE4X5_STS)
 */
+#define STS_GPI    0x04000000       /* General Purpose Port Interrupt */
 #define STS_BE     0x03800000       /* Bus Error Bits */
 #define STS_TS     0x00700000       /* Transmit Process State */
 #define STS_RS     0x000e0000       /* Receive Process State */
 #define STS_NIS    0x00010000       /* Normal Interrupt Summary */
 #define STS_AIS    0x00008000       /* Abnormal Interrupt Summary */
 #define STS_ER     0x00004000       /* Early Receive */
+#define STS_FBE    0x00002000       /* Fatal Bus Error */
 #define STS_SE     0x00002000       /* System Error */
 #define STS_LNF    0x00001000       /* Link Fail */
 #define STS_FD     0x00000800       /* Full-Duplex Short Frame Received */
 #define STS_TM     0x00000800       /* Timer Expired (DC21041) */
+#define STS_ETI    0x00000400       /* Early Transmit Interupt */
 #define STS_AT     0x00000400       /* AUI/TP Pin */
 #define STS_RWT    0x00000200       /* Receive Watchdog Time-Out */
 #define STS_RPS    0x00000100       /* Receive Process Stopped */
@@ -268,6 +294,7 @@
 #define STS_RI     0x00000040       /* Receive Interrupt */
 #define STS_UNF    0x00000020       /* Transmit Underflow */
 #define STS_LNP    0x00000010       /* Link Pass */
+#define STS_ANC    0x00000010       /* Autonegotiation Complete */
 #define STS_TJT    0x00000008       /* Transmit Jabber Time-Out */
 #define STS_TU     0x00000004       /* Transmit Buffer Unavailable */
 #define STS_TPS    0x00000002       /* Transmit Process Stopped */
@@ -300,8 +327,10 @@
 #define INT_CANCEL 0x0001ffff       /* For zeroing all interrupt sources */
 
 /*
-** DC21040 Operation Mode Register (DE4X5_OMR)
+** Operation Mode Register (DE4X5_OMR)
 */
+#define OMR_SC     0x80000000       /* Special Capture Effect Enable */
+#define OMR_RA     0x40000000       /* Receive All */
 #define OMR_SDP    0x02000000       /* SD Polarity - MUST BE ASSERTED */
 #define OMR_SCR    0x01000000       /* Scrambler Mode */
 #define OMR_PCS    0x00800000       /* PCS Function */
@@ -326,27 +355,31 @@
 #define OMR_SR     0x00000002       /* Start/Stop Receive */
 #define OMR_HP     0x00000001       /* Hash/Perfect Receive Filtering Mode */
 
-#define TR_72      0x00000000       /* Threshold set to 72 bytes */
-#define TR_96      0x00004000       /* Threshold set to 96 bytes */
-#define TR_128     0x00008000       /* Threshold set to 128 bytes */
-#define TR_160     0x0000c000       /* Threshold set to 160 bytes */
+#define TR_72      0x00000000       /* Threshold set to 72 (128) bytes */
+#define TR_96      0x00004000       /* Threshold set to 96 (256) bytes */
+#define TR_128     0x00008000       /* Threshold set to 128 (512) bytes */
+#define TR_160     0x0000c000       /* Threshold set to 160 (1024) bytes */
 
 /*
 ** DC21040 Interrupt Mask Register (DE4X5_IMR)
 */
+#define IMR_GPM    0x04000000       /* General Purpose Port Mask */
 #define IMR_NIM    0x00010000       /* Normal Interrupt Summary Mask */
 #define IMR_AIM    0x00008000       /* Abnormal Interrupt Summary Mask */
 #define IMR_ERM    0x00004000       /* Early Receive Mask */
+#define IMR_FBM    0x00002000       /* Fatal Bus Error Mask */
 #define IMR_SEM    0x00002000       /* System Error Mask */
 #define IMR_LFM    0x00001000       /* Link Fail Mask */
 #define IMR_FDM    0x00000800       /* Full-Duplex (Short Frame) Mask */
 #define IMR_TMM    0x00000800       /* Timer Expired Mask (DC21041) */
+#define IMR_ETM    0x00000400       /* Early Transmit Interrupt Mask */
 #define IMR_ATM    0x00000400       /* AUI/TP Switch Mask */
 #define IMR_RWM    0x00000200       /* Receive Watchdog Time-Out Mask */
 #define IMR_RSM    0x00000100       /* Receive Stopped Mask */
 #define IMR_RUM    0x00000080       /* Receive Buffer Unavailable Mask */
 #define IMR_RIM    0x00000040       /* Receive Interrupt Mask */
 #define IMR_UNM    0x00000020       /* Underflow Interrupt Mask */
+#define IMR_ANM    0x00000010       /* Autonegotiation Complete Mask */
 #define IMR_LPM    0x00000010       /* Link Pass */
 #define IMR_TJM    0x00000008       /* Transmit Time-Out Jabber Mask */
 #define IMR_TUM    0x00000004       /* Transmit Buffer Unavailable Mask */
@@ -354,13 +387,7 @@
 #define IMR_TIM    0x00000001       /* Transmit Interrupt Mask */
 
 /*
-** DC21040 Missed Frames Counter (DE4X5_MFC)
-*/
-#define MFC_OVFL   0x00010000       /* Missed Frames Counter Overflow Bit */
-#define MFC_CNTR   0x0000ffff       /* Missed Frames Counter Bits */
-
-/*
-** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
+** Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
 */
 #define MFC_FOCO   0x10000000       /* FIFO Overflow Counter Overflow Bit */
 #define MFC_FOC    0x0ffe0000       /* FIFO Overflow Counter Bits */
@@ -461,7 +488,7 @@
 ** MII Management Auto Negotiation Advertisement Register
 */
 #define MII_ANA_TAF  0x03e0        /* Technology Ability Field */
-#define MII_ANA_T4AM 0x0400        /* T4 Technology Ability Mask */
+#define MII_ANA_T4AM 0x0200        /* T4 Technology Ability Mask */
 #define MII_ANA_TXAM 0x0180        /* TX Technology Ability Mask */
 #define MII_ANA_FDAM 0x0140        /* Full Duplex Technology Ability Mask */
 #define MII_ANA_HDAM 0x02a0        /* Half Duplex Technology Ability Mask */
@@ -476,7 +503,7 @@
 #define MII_ANLPA_ACK  0x4000      /* Remote Acknowledge */
 #define MII_ANLPA_RF   0x2000      /* Remote Fault */
 #define MII_ANLPA_TAF  0x03e0      /* Technology Ability Field */
-#define MII_ANLPA_T4AM 0x0400      /* T4 Technology Ability Mask */
+#define MII_ANLPA_T4AM 0x0200      /* T4 Technology Ability Mask */
 #define MII_ANLPA_TXAM 0x0180      /* TX Technology Ability Mask */
 #define MII_ANLPA_FDAM 0x0140      /* Full Duplex Technology Ability Mask */
 #define MII_ANLPA_HDAM 0x02a0      /* Half Duplex Technology Ability Mask */
@@ -547,6 +574,8 @@
 #define SROM_100BASEFF 0x0008      /*  100BASE-FX full duplex */
 
 #define BLOCK_LEN      0x7f        /* Extended blocks length mask */
+#define EXT_FIELD      0x40        /* Extended blocks extension field bit */
+#define MEDIA_CODE     0x3f        /* Extended blocks media code mask */
 
 /*
 ** SROM Compact Format Block Masks
@@ -589,14 +618,18 @@
 #define GEP_CTRL 0x00000100        /* GEP control bit                  */
 
 /*
-** DC21040 SIA Status Register (DE4X5_SISR)
+** SIA Status Register (DE4X5_SISR)
 */
 #define SISR_LPC   0xffff0000      /* Link Partner's Code Word */
 #define SISR_LPN   0x00008000      /* Link Partner Negotiable */
 #define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State */
-#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected */
+#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041) */
+#define SISR_TRF   0x00000800      /* Transmit Remote Fault */
+#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142) */
 #define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
+#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity */
 #define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity */
+#define SISR_ARA   0x00000100      /* AUI Receive Port Activity */
 #define SISR_SRA   0x00000100      /* Selected Port Receive Activity */
 #define SISR_DAO   0x00000080      /* PLL All One */
 #define SISR_DAZ   0x00000040      /* PLL All Zero */
@@ -606,7 +639,7 @@
 #define SISR_LKF   0x00000004      /* Link Fail Status */
 #define SISR_NCR   0x00000002      /* Network Connection Error */
 #define SISR_PAUI  0x00000001      /* AUI_TP Indication */
-#define SIA_RESET  0x00000000      /* SIA Reset */
+#define SISR_MRA   0x00000001      /* MII Receive Port Activity */
 
 #define ANS_NDIS   0x00000000      /* Nway disable */
 #define ANS_TDIS   0x00001000      /* Transmit Disable */
@@ -617,7 +650,7 @@
 #define ANS_LCHK   0x00006000      /* Link Check */
 
 /*
-** DC21040 SIA Connectivity Register (DE4X5_SICR)
+** SIA Connectivity Register (DE4X5_SICR)
 */
 #define SICR_SDM   0xffff0000       /* SIA Diagnostics Mode */
 #define SICR_OE57  0x00008000       /* Output Enable 5 6 7 */
@@ -636,14 +669,14 @@
 #define SICR_SIM   0x00000040       /* Serial Interface Input Multiplexer */
 #define SICR_ENI   0x00000020       /* Encoder Input Multiplexer */
 #define SICR_EDP   0x00000010       /* SIA PLL External Input Enable */
-#define SICR_AUI   0x00000008       /* 10Base-T or AUI */
+#define SICR_AUI   0x00000008       /* 10Base-T (0) or AUI (1) */
 #define SICR_CAC   0x00000004       /* CSR Auto Configuration */
 #define SICR_PS    0x00000002       /* Pin AUI/TP Selection */
 #define SICR_SRL   0x00000001       /* SIA Reset */
-#define SICR_RESET 0xffff0000       /* Reset value for SICR */
+#define SIA_RESET  0x00000000       /* SIA Reset Value */
 
 /*
-** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
+** SIA Transmit and Receive Register (DE4X5_STRR)
 */
 #define STRR_TAS   0x00008000       /* 10Base-T/AUI Autosensing Enable */
 #define STRR_SPP   0x00004000       /* Set Polarity Plus */
@@ -663,8 +696,20 @@
 #define STRR_RESET 0xffffffff       /* Reset value for STRR */
 
 /*
-** DC21040 SIA General Register (DE4X5_SIGR)
+** SIA General Register (DE4X5_SIGR)
 */
+#define SIGR_RMI   0x40000000       /* Receive Match Interrupt */
+#define SIGR_GI1   0x20000000       /* General Port Interrupt 1 */
+#define SIGR_GI0   0x10000000       /* General Port Interrupt 0 */
+#define SIGR_CWE   0x08000000       /* Control Write Enable */
+#define SIGR_RME   0x04000000       /* Receive Match Enable */
+#define SIGR_GEI1  0x02000000       /* GEP Interrupt Enable on Port 1 */
+#define SIGR_GEI0  0x01000000       /* GEP Interrupt Enable on Port 0 */
+#define SIGR_LGS3  0x00800000       /* LED/GEP3 Select */
+#define SIGR_LGS2  0x00400000       /* LED/GEP2 Select */
+#define SIGR_LGS1  0x00200000       /* LED/GEP1 Select */
+#define SIGR_LGS0  0x00100000       /* LED/GEP0 Select */
+#define SIGR_MD    0x000f0000       /* General Purpose Mode and Data */
 #define SIGR_LV2   0x00008000       /* General Purpose LED2 value */
 #define SIGR_LE2   0x00004000       /* General Purpose LED2 enable */
 #define SIGR_FRL   0x00002000       /* Force Receiver Low */
@@ -687,7 +732,8 @@
 ** Receive Descriptor Bit Summary
 */
 #define R_OWN      0x80000000       /* Own Bit */
-#define RD_FL      0x7fff0000       /* Frame Length */
+#define RD_FF      0x40000000       /* Filtering Fail */
+#define RD_FL      0x3fff0000       /* Frame Length */
 #define RD_ES      0x00008000       /* Error Summary */
 #define RD_LE      0x00004000       /* Length Error */
 #define RD_DT      0x00003000       /* Data Type */
@@ -699,6 +745,7 @@
 #define RD_CS      0x00000040       /* Collision Seen */
 #define RD_FT      0x00000020       /* Frame Type */
 #define RD_RJ      0x00000010       /* Receive Watchdog */
+#define RD_RE      0x00000008       /* Report on MII Error */
 #define RD_DB      0x00000004       /* Dribbling Bit */
 #define RD_CE      0x00000002       /* CRC Error */
 #define RD_OF      0x00000001       /* Overflow */
@@ -734,40 +781,39 @@
 #define TD_TCH     0x01000000       /* Second Address Chained */
 #define TD_DPD     0x00800000       /* Disabled Padding */
 #define TD_FT0     0x00400000       /* Filtering Type */
-#define TD_RBS2    0x003ff800       /* Buffer 2 Size */
-#define TD_RBS1    0x000007ff       /* Buffer 1 Size */
+#define TD_TBS2    0x003ff800       /* Buffer 2 Size */
+#define TD_TBS1    0x000007ff       /* Buffer 1 Size */
 
 #define PERFECT_F  0x00000000
 #define HASH_F     TD_FT0
 #define INVERSE_F  TD_FT1
-#define HASH_O_F   TD_FT1| TD_F0
+#define HASH_O_F   (TD_FT1 | TD_F0)
 
 /*
 ** Media / mode state machine definitions
 */
-#define NC              0x0000     /* No Connection */
-#define TP              0x0001     /* 10Base-T */
-#define TP_NW           0x0002     /* 10Base-T with Nway */
-#define BNC             0x0004     /* Thinwire */
-#define AUI             0x0008     /* Thickwire */
+#define NC              0x0000     /* No Connection                        */
+#define TP              0x0001     /* 10Base-T                             */
+#define TP_NW           0x0002     /* 10Base-T with Nway                   */
+#define BNC             0x0004     /* Thinwire                             */
+#define AUI             0x0008     /* Thickwire                            */
 #define BNC_AUI         0x0010     /* BNC/AUI on DC21040 indistinguishable */
-#define ANS             0x0020     /* Intermediate AutoNegotiation State */
-#define ANS_1           0x0021     /* Intermediate AutoNegotiation State */
-
-#define _10Mb           0x0040     /* 10Mb/s Ethernet */
-#define _100Mb          0x0080     /* 100Mb/s Ethernet */
-#define SPD_DET         0x0100     /* Parallel speed detection */
-#define INIT            0x0200     /* Initial state */
-#define EXT_SIA         0x0400     /* External SIA for motherboard chip */
-#define ANS_SUSPECT     0x0802     /* Suspect the ANS (TP) port is down */
-#define TP_SUSPECT      0x0803     /* Suspect the TP port is down */
-#define BNC_AUI_SUSPECT 0x0804     /* Suspect the BNC or AUI port is down */
-#define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down */
-#define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down */
-#define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down */
+#define ANS             0x0020     /* Intermediate AutoNegotiation State   */
+#define _10Mb           0x0040     /* 10Mb/s Ethernet                      */
+#define _100Mb          0x0080     /* 100Mb/s Ethernet                     */
+#define SPD_DET         0x0100     /* Parallel speed detection             */
+#define INIT            0x0200     /* Initial state                        */
+#define EXT_SIA         0x0400     /* External SIA for motherboard chip    */
+#define ANS_SUSPECT     0x0802     /* Suspect the ANS (TP) port is down    */
+#define TP_SUSPECT      0x0803     /* Suspect the TP port is down          */
+#define BNC_AUI_SUSPECT 0x0804     /* Suspect the BNC or AUI port is down  */
+#define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down     */
+#define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down         */
+#define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down         */
+#define MII             0x1000     /* MII on the 21143                     */
 
-#define AUTO            0x4000     /* Auto sense the media or speed */
-#define TIMER_CB        0x80000000 /* Timer callback detection */
+#define AUTO            0x4000     /* Auto sense the media or speed        */
+#define TIMER_CB        0x80000000 /* Timer callback detection             */
 
 /*
 ** DE4X5 DEBUG Options
@@ -798,7 +844,6 @@
 #define POLL_DEMAND          1
 
 #define LOST_MEDIA_THRESHOLD 3
-#define LOST_MEDIA           (lp->lostMedia > LOST_MEDIA_THRESHOLD)
 
 #define MASK_INTERRUPTS      1
 #define UNMASK_INTERRUPTS    0
@@ -859,7 +904,7 @@
     }\
     omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
     outl(omr, DE4X5_OMR);\
-    lp->cache.gep = 0;\
+    if (!lp->useSROM) lp->cache.gep = 0;\
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -887,7 +932,7 @@
     }\
     if (fdx) omr |= OMR_FDX;\
     outl(omr, DE4X5_OMR);\
-    lp->cache.gep = 0;\
+    if (!lp->useSROM) lp->cache.gep = 0;\
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -906,7 +951,6 @@
     mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
     omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr, DE4X5_OMR);\
-    lp->cache.gep = 0;\
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     outl(omr, DE4X5_OMR);\
@@ -934,7 +978,7 @@
 ** Recognised commands for the driver 
 */
 #define DE4X5_GET_HWADDR	0x01 /* Get the hardware address */
-#define DE4X5_SET_HWADDR	0x02 /* Get the hardware address */
+#define DE4X5_SET_HWADDR	0x02 /* Set the hardware address */
 #define DE4X5_SET_PROM  	0x03 /* Set Promiscuous Mode */
 #define DE4X5_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
 #define DE4X5_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.1.36/linux/drivers/net/depca.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/depca.c	Mon May 12 10:35:41 1997
@@ -804,7 +804,7 @@
     dev_tint(dev);
   } else if (skb->len > 0) {
     /* Enforce 1 process per h/w access */
-    if (set_bit(0, (void*)&dev->tbusy) != 0) {
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
       printk("%s: Transmitter access conflict.\n", dev->name);
       status = -1;
     } else {
diff -u --recursive --new-file v2.1.36/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.1.36/linux/drivers/net/dlci.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/dlci.c	Mon May 12 10:35:41 1997
@@ -248,7 +248,7 @@
 
 	dlp = dev->priv;
 
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
 	else
 	{
diff -u --recursive --new-file v2.1.36/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.1.36/linux/drivers/net/eepro.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/eepro.c	Mon May 12 10:35:41 1997
@@ -714,7 +714,7 @@
 	}
 
 	/* Block a timer-based transmit from overlapping. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.36/linux/drivers/net/eepro100.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/eepro100.c	Mon May 12 10:35:41 1997
@@ -1033,7 +1033,7 @@
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	   If this ever occurs the queue layer is doing something evil! */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		int tickssofar = jiffies - dev->trans_start;
 		if (tickssofar < TX_TIMEOUT - 2)
 			return 1;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.1.36/linux/drivers/net/eexpress.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/eexpress.c	Mon May 12 10:35:41 1997
@@ -94,6 +94,7 @@
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -301,7 +302,7 @@
  * checks for presence of EtherExpress card
  */
 
-int express_probe(struct device *dev)
+__initfunc(int express_probe(struct device *dev))
 {
 	unsigned short *port;
 	static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
@@ -525,7 +526,7 @@
 		}
 	}
   
-	if (set_bit(0,(void *)&dev->tbusy))
+	if (test_and_set_bit(0,(void *)&dev->tbusy))
 	{
 		lp->stats.tx_dropped++;
 	}
@@ -913,7 +914,7 @@
  * than one card in a machine.
  */
 
-static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
+__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr))
 {
 	unsigned short hw_addr[3];
 	unsigned char buswidth;
@@ -1034,8 +1035,8 @@
  * Read a word from the EtherExpress on-board serial EEPROM.
  * The EEPROM contains 64 words of 16 bits.
  */
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
-					 unsigned char location)
+__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+						    unsigned char location))
 {
 	unsigned short cmd = 0x180|(location&0x7f);
 	unsigned short rval = 0,wval = EC_CS|i586_RST;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.1.36/linux/drivers/net/eth16i.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/eth16i.c	Mon May 12 10:35:41 1997
@@ -932,7 +932,7 @@
 	/* Turn off TX interrupts */
 	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
 
-	if(set_bit(0, (void *)&dev->tbusy) != 0)
+	if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.1.36/linux/drivers/net/ewrk3.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/ewrk3.c	Mon May 12 10:35:41 1997
@@ -767,7 +767,7 @@
     ** Block a timer-based transmit from overlapping.  This could better be
     ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
     */
-    if (set_bit(0, (void*)&dev->tbusy) != 0)
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
       printk("%s: Transmitter access conflict.\n", dev->name);
 
     DISABLE_IRQs;                      /* So that the page # remains correct */
@@ -783,7 +783,7 @@
 	/*
 	** Set up shared memory window and pointer into the window
 	*/
-	while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+	while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
 	if (lp->shmem_length == IO_ONLY) {
 	  outb(page, EWRK3_IOPR);
 	} else if (lp->shmem_length == SHMEM_2K) {
@@ -953,7 +953,7 @@
       ** Preempt any process using the current page register. Check for
       ** an existing lock to reduce time taken in I/O transactions.
       */
-      if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) {   /* Assert lock */
+      if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) {   /* Assert lock */
 	if (lp->shmem_length == IO_ONLY) {              /* Get existing page */
 	  tmpPage = inb(EWRK3_IOPR);
 	} else {
@@ -1217,7 +1217,7 @@
   u16 hashcode;
   s32 crc, poly = CRC_POLYNOMIAL_LE;
 
-  while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+  while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
 
   if (lp->shmem_length == IO_ONLY) {
     outb(0, EWRK3_IOPR);
@@ -1723,7 +1723,7 @@
     break;
   case EWRK3_GET_MCA:                /* Get the multicast address table */
     if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
-      while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+      while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
       if (lp->shmem_length == IO_ONLY) {
 	outb(0, EWRK3_IOPR);
 	outw(PAGE0_HTE, EWRK3_PIR1);
diff -u --recursive --new-file v2.1.36/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.1.36/linux/drivers/net/fmv18x.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/fmv18x.c	Mon May 12 10:35:41 1997
@@ -348,7 +348,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c
--- v2.1.36/linux/drivers/net/hdlcdrv.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/hdlcdrv.c	Mon May 12 10:35:41 1997
@@ -288,7 +288,7 @@
 	
 	if (!s || s->magic != HDLCDRV_MAGIC) 
 		return;
-	if (set_bit(0, &s->hdlcrx.in_hdlc_rx))
+	if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx))
 		return;
 
 	while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) {
@@ -387,7 +387,7 @@
 
 	if (!s || s->magic != HDLCDRV_MAGIC) 
 		return;
-	if (set_bit(0, &s->hdlctx.in_hdlc_tx))
+	if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx))
 		return;
 	for (;;) {
 		if (s->hdlctx.numbits >= 16) {
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.36/linux/drivers/net/ibmtr.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/ibmtr.c	Mon May 12 10:35:41 1997
@@ -1495,7 +1495,7 @@
 		return 0;
 	}
 
-	if (set_bit(0,(void *)&dev->tbusy)!=0)
+	if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
 		DPRINTK("Transmitter access conflict\n");
 	else {
 		/* Save skb; we'll need it when the adapter asks for the data */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.36/linux/drivers/net/lance.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/lance.c	Mon May 12 10:35:41 1997
@@ -834,12 +834,12 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 
-	if (set_bit(0, (void*)&lp->lock) != 0) {
+	if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
 		if (lance_debug > 0)
 			printk("%s: tx queue lock!.\n", dev->name);
 		/* don't clear dev->tbusy flag. */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.1.36/linux/drivers/net/ltpc.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/ltpc.c	Mon May 12 10:35:41 1997
@@ -1259,7 +1259,7 @@
 		if(debug&DEBUG_VERBOSE) printk("waiting\n");
 		/* if it's in process, wait a bit for it to finish */
 		timeout = jiffies+HZ; 
-		add_timer(&ltpc_timer)
+		add_timer(&ltpc_timer);
 		while(del_timer(&ltpc_timer) && (timeout > jiffies))
 		{
 			add_timer(&ltpc_timer);
diff -u --recursive --new-file v2.1.36/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c
--- v2.1.36/linux/drivers/net/mkiss.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/mkiss.c	Mon May 12 10:35:41 1997
@@ -109,7 +109,7 @@
 			break;
 
 		/* Not in use ? */
-		if (!set_bit(AXF_INUSE, &axp->ctrl.flags))
+		if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags))
 			break;
 	}
 
@@ -165,7 +165,7 @@
 	if (ax->xbuff)
 		kfree(ax->xbuff);
 	ax->xbuff = NULL;
-	if (!clear_bit(AXF_INUSE, &ax->flags))
+	if (!test_and_clear_bit(AXF_INUSE, &ax->flags))
 		printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name);
 }
 
@@ -244,7 +244,7 @@
 /* Set the "sending" flag.  This must be atomic, hence the ASM. */
 static inline void ax_lock(struct ax_disp *ax)
 {
-	if (set_bit(0, (void *)&ax->dev->tbusy))
+	if (test_and_set_bit(0, (void *)&ax->dev->tbusy))
 		printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name);
 }
 
@@ -252,7 +252,7 @@
 /* Clear the "sending" flag.  This must be atomic, hence the ASM. */
 static inline void ax_unlock(struct ax_disp *ax)
 {
-	if (!clear_bit(0, (void *)&ax->dev->tbusy))
+	if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy))
 		printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name);
 }
 
@@ -551,7 +551,7 @@
 	/* Read the characters out of the buffer */
 	while (count--) {
 		if (fp != NULL && *fp++) {
-			if (!set_bit(AXF_ERROR, &ax->flags))
+			if (!test_and_set_bit(AXF_ERROR, &ax->flags))
 				ax->rx_errors++;
 			cp++;
 			continue;
@@ -709,7 +709,7 @@
 			if (test_bit(AXF_KEEPTEST, &ax->flags))
 				clear_bit(AXF_KEEPTEST, &ax->flags);
 
-			if (!clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
+			if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
 				ax_bump(ax);
 
 			clear_bit(AXF_ESCAPE, &ax->flags);
@@ -720,11 +720,11 @@
 			set_bit(AXF_ESCAPE, &ax->flags);
 			return;
 		case ESC_ESC:
-			if (clear_bit(AXF_ESCAPE, &ax->flags))
+			if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
 				s = ESC;
 			break;
 		case ESC_END:
-			if (clear_bit(AXF_ESCAPE, &ax->flags))
+			if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
 				s = END;
 			break;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.1.36/linux/drivers/net/myri_sbus.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/myri_sbus.c	Mon May 12 10:35:41 1997
@@ -584,7 +584,7 @@
 		return 0;
 	}
 
-	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		DTX(("tbusy, maybe a race? returning 1\n"));
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.1.36/linux/drivers/net/ni52.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/ni52.c	Mon May 12 10:35:41 1997
@@ -1171,12 +1171,12 @@
 		return 0;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy)) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy)) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 #if(NUM_XMIT_BUFFS > 1)
-	else if(set_bit(0,(void *) &p->lock)) {
+	else if(test_and_set_bit(0,(void *) &p->lock)) {
 		printk("%s: Queue was locked\n",dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.1.36/linux/drivers/net/ni65.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/ni65.c	Mon May 12 10:35:41 1997
@@ -804,7 +804,7 @@
 		return;
 	}
 
-	if(set_bit(0,(int *) &dev->interrupt)) {
+	if(test_and_set_bit(0,(int *) &dev->interrupt)) {
 		printk("ni65: oops .. interrupt while proceeding interrupt\n");
 		return;
 	}
@@ -1087,11 +1087,11 @@
 		dev->trans_start = jiffies;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		 printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
 		 return 1;
 	}
-	if (set_bit(0, (void*)&p->lock)) {
+	if (test_and_set_bit(0, (void*)&p->lock)) {
 		printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.1.36/linux/drivers/net/pcnet32.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/pcnet32.c	Mon May 12 10:35:41 1997
@@ -594,12 +594,12 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 
-	if (set_bit(0, (void*)&lp->lock) != 0) {
+	if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
 		if (pcnet32_debug > 0)
 			printk("%s: tx queue lock!.\n", dev->name);
 		/* don't clear dev->tbusy flag. */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.1.36/linux/drivers/net/plip.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/plip.c	Mon May 12 10:35:41 1997
@@ -910,7 +910,7 @@
 		return 0;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.36/linux/drivers/net/ppp.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/ppp.c	Mon May 12 10:35:41 1997
@@ -1291,7 +1291,7 @@
  * The total length includes the protocol data.
  * Lock the user information buffer.
  */
-	if (set_bit (0, &ppp->ubuf->locked)) {
+	if (test_and_set_bit (0, &ppp->ubuf->locked)) {
 		if (ppp->flags & SC_DEBUG)
 			printk (KERN_DEBUG
 				"ppp_us_queue: can't get lock\n");
@@ -1698,7 +1698,7 @@
 		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
 			return 0;
 
-		if (set_bit (0, &ppp->ubuf->locked) != 0) {
+		if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
 			if (ppp->flags & SC_DEBUG)
 				printk (KERN_DEBUG
 				     "ppp_tty_read: sleeping(ubuf)\n");
@@ -2584,7 +2584,7 @@
 		poll_wait(&ppp->write_wait, wait);
 
 		/* Must lock the user buffer area while checking. */
-		if(set_bit(0, &ppp->ubuf->locked) == 0) {
+		if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) {
 			if(ppp->ubuf->head != ppp->ubuf->tail)
 				mask |= POLLIN | POLLRDNORM;
 			clear_bit(0, &ppp->ubuf->locked);
@@ -3130,7 +3130,7 @@
 
 	while (ctl) {
 		ppp = ctl2ppp (ctl);
-		if (!set_bit(0, &ppp->inuse)) {
+		if (!test_and_set_bit(0, &ppp->inuse)) {
 			if (ppp->sc_xfer == pid_value) {
 				ppp->sc_xfer = 0;
 				return (ppp);
@@ -3160,7 +3160,7 @@
 
 	while (ctl) {
 		ppp = ctl2ppp (ctl);
-		if (!set_bit(0, &ppp->inuse))
+		if (!test_and_set_bit(0, &ppp->inuse))
 			return (ppp);
 		ctl = ctl->next;
 		if (++if_num == max_dev)
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.1.36/linux/drivers/net/sdla.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sdla.c	Mon May 12 10:35:41 1997
@@ -657,7 +657,7 @@
 	if (skb == NULL) 
 		return(0);
 
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
 	else
 	{
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c
--- v2.1.36/linux/drivers/net/sdla_fr.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sdla_fr.c	Mon May 12 10:35:41 1997
@@ -440,7 +440,7 @@
 	if (dev->start)
 		return -EBUSY		/* only one open is allowed */
 	;
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 	if (!card->open_cnt)
@@ -489,7 +489,7 @@
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 	dev->start = 0;
@@ -574,7 +574,7 @@
 	sdla_t* card = chan->card;
 	int retry = 0;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -584,7 +584,7 @@
 		return 1;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy))
+	if (test_and_set_bit(0, (void*)&dev->tbusy))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c
--- v2.1.36/linux/drivers/net/sdla_ppp.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sdla_ppp.c	Mon May 12 10:35:41 1997
@@ -286,7 +286,7 @@
 	if (dev->start)
 		return -EBUSY		/* only one open is allowed */
 	;
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card))
@@ -365,7 +365,7 @@
 {
 	sdla_t* card = dev->priv;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 	dev->start = 0;
@@ -441,7 +441,7 @@
 	sdla_t* card = dev->priv;
 	int retry = 0;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -451,7 +451,7 @@
 		return 1;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy))
+	if (test_and_set_bit(0, (void*)&dev->tbusy))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c
--- v2.1.36/linux/drivers/net/sdla_x25.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sdla_x25.c	Mon May 12 10:35:41 1997
@@ -476,7 +476,7 @@
 	if (dev->start)
 		return -EBUSY		/* only one open is allowed */
 	;
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 
@@ -503,7 +503,7 @@
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
 	;
 	dev->start = 0;
@@ -590,7 +590,7 @@
 	sdla_t* card = chan->card;
 	int retry = 0, queued = 0;
 
-	if (set_bit(0, (void*)&card->wandev.critical))
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: if_send() hit critical section!\n",
@@ -600,7 +600,7 @@
 		return 1;
 	}
 
-	if (set_bit(0, (void*)&dev->tbusy))
+	if (test_and_set_bit(0, (void*)&dev->tbusy))
 	{
 #ifdef _DEBUG_
 		printk(KERN_INFO "%s: Tx collision on interface %s!\n",
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.1.36/linux/drivers/net/sdlamain.c	Sun Feb  2 05:18:41 1997
+++ linux/drivers/net/sdlamain.c	Mon May 12 10:35:41 1997
@@ -332,7 +332,7 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return 0
 	;
-	if (set_bit(0, (void*)&wandev->critical))
+	if (test_and_set_bit(0, (void*)&wandev->critical))
 		return -EAGAIN
 	;
 	card = wandev->private;
@@ -364,7 +364,7 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV
 	;
-	if (set_bit(0, (void*)&wandev->critical))
+	if (test_and_set_bit(0, (void*)&wandev->critical))
 		return -EAGAIN
 	;
 	switch (cmd)
@@ -514,7 +514,7 @@
 		sdla_t* card = &card_array[i];
 
 		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
-		    !set_bit(0, (void*)&card->wandev.critical))
+		    !test_and_set_bit(0, (void*)&card->wandev.critical))
 		{
 			card->poll(card);
 			card->wandev.critical = 0;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.1.36/linux/drivers/net/seeq8005.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/seeq8005.c	Mon May 12 10:35:41 1997
@@ -392,7 +392,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.1.36/linux/drivers/net/sk_g16.c	Fri Apr  4 08:52:21 1997
+++ linux/drivers/net/sk_g16.c	Mon May 12 10:35:41 1997
@@ -68,6 +68,7 @@
 #include <asm/io.h>
 #include <asm/bitops.h> 
 #include <linux/errno.h>
+#include <linux/init.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -532,7 +533,7 @@
  *                         (detachable devices only).
  */
 
-int SK_init(struct device *dev)
+__initfunc(int SK_init(struct device *dev))
 {
 	int ioaddr         = 0;            /* I/O port address used for POS regs */
 	int *port, ports[] = SK_IO_PORTS;  /* SK_G16 supported ports */
@@ -616,7 +617,7 @@
  *     94/06/30  pwe  SK_ADDR now checked and at the correct place
 -*/
 
-int SK_probe(struct device *dev, short ioaddr)
+__initfunc(int SK_probe(struct device *dev, short ioaddr))
 {
     int i,j;                /* Counters */
     int sk_addr_flag = 0;   /* SK ADDR correct? 1 - no, 0 - yes */
@@ -1210,7 +1211,7 @@
      * This means check if we are already in. 
      */
 
-    if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ 
+    if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ 
     {
 	printk("%s: Transmitter access conflict.\n", dev->name);
     }
@@ -1740,7 +1741,7 @@
  *     YY/MM/DD  uid  Description
 -*/
 
-unsigned int SK_rom_addr(void)
+__initfunc(unsigned int SK_rom_addr(void))
 {
     int i,j;
     int rom_found = 0;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.1.36/linux/drivers/net/skeleton.c	Sun Feb  2 05:18:42 1997
+++ linux/drivers/net/skeleton.c	Mon May 12 10:35:41 1997
@@ -56,6 +56,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -70,7 +71,7 @@
 /* First, a few definitions that the brave might change. */
 
 /* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int netcard_portlist[] =
+static unsigned int netcard_portlist[] __initdata =
    { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -126,8 +127,8 @@
 struct netdev_entry netcard_drv =
 {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
 #else
-int
-netcard_probe(struct device *dev)
+__initfunc(int
+netcard_probe(struct device *dev))
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -154,7 +155,7 @@
  * probes on the ISA bus. A good device probes avoids doing writes, and
  * verifies that the correct device exists and functions.
  */
-static int netcard_probe1(struct device *dev, int ioaddr)
+__initfunc(static int netcard_probe1(struct device *dev, int ioaddr))
 {
 	static unsigned version_printed = 0;
 	int i;
@@ -365,7 +366,7 @@
 	 * Block a timer-based transmit from overlapping. This could better be
 	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	 */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.1.36/linux/drivers/net/slip.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/slip.c	Mon May 12 10:35:41 1997
@@ -123,7 +123,7 @@
 	  if (slp == NULL)
 	    break;
 	  /* Not in use ? */
-	  if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+	  if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
 	    break;
 	}
 	/* SLP is set.. */
@@ -207,7 +207,7 @@
 	sl->slcomp = NULL;
 #endif
 
-	if (!clear_bit(SLF_INUSE, &sl->flags)) {
+	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
 		printk("%s: sl_free for already free unit.\n", sl->dev->name);
 	}
 }
@@ -317,7 +317,7 @@
 static inline void
 sl_lock(struct slip *sl)
 {
-	if (set_bit(0, (void *) &sl->dev->tbusy))  {
+	if (test_and_set_bit(0, (void *) &sl->dev->tbusy))  {
 		printk("%s: trying to lock already locked device!\n", sl->dev->name);
         }
 }
@@ -327,7 +327,7 @@
 static inline void
 sl_unlock(struct slip *sl)
 {
-	if (!clear_bit(0, (void *)&sl->dev->tbusy))  {
+	if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))  {
 		printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
         }
 }
@@ -661,7 +661,7 @@
 	/* Read the characters out of the buffer */
 	while (count--) {
 		if (fp && *fp++) {
-			if (!set_bit(SLF_ERROR, &sl->flags))  {
+			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {
 				sl->rx_errors++;
 			}
 			cp++;
@@ -843,7 +843,7 @@
 		if (test_bit(SLF_KEEPTEST, &sl->flags))
 			clear_bit(SLF_KEEPTEST, &sl->flags);
 
-		if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
+		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
 			sl_bump(sl);
 		}
 		clear_bit(SLF_ESCAPE, &sl->flags);
@@ -854,12 +854,12 @@
 		set_bit(SLF_ESCAPE, &sl->flags);
 		return;
 	 case ESC_ESC:
-		if (clear_bit(SLF_ESCAPE, &sl->flags))  {
+		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {
 			s = ESC;
 		}
 		break;
 	 case ESC_END:
-		if (clear_bit(SLF_ESCAPE, &sl->flags))  {
+		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {
 			s = END;
 		}
 		break;
@@ -928,7 +928,7 @@
 		if (test_bit(SLF_KEEPTEST, &sl->flags))
 			clear_bit(SLF_KEEPTEST, &sl->flags);
 
-		if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
+		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
 			sl_bump(sl);
 		}
 		sl->rcount = 0;
diff -u --recursive --new-file v2.1.36/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.1.36/linux/drivers/net/smc9194.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/smc9194.c	Mon May 12 10:35:41 1997
@@ -1245,7 +1245,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
 		dev_kfree_skb (skb, FREE_WRITE);
 	} else {
diff -u --recursive --new-file v2.1.36/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c
--- v2.1.36/linux/drivers/net/soundmodem/sm.c	Fri Apr  4 08:52:22 1997
+++ linux/drivers/net/soundmodem/sm.c	Mon May 12 10:35:41 1997
@@ -56,6 +56,7 @@
 #include <asm/bitops.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 #include "sm.h"
 
 /* --------------------------------------------------------------------- */
@@ -662,10 +663,7 @@
 
 /* --------------------------------------------------------------------- */
 
-#ifdef MODULE
-static
-#endif /* MODULE */
-int sm_init(void)
+__initfunc(int sm_init(void))
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -800,7 +798,7 @@
  * modem: afsk1200, fsk9600
  */
 
-void sm_setup(char *str, int *ints)
+__initfunc(void sm_setup(char *str, int *ints))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.36/linux/drivers/net/strip.c	Thu Feb 27 10:57:31 1997
+++ linux/drivers/net/strip.c	Mon May 12 10:35:41 1997
@@ -891,7 +891,7 @@
      */
     strip_info->idle_timer.expires  = jiffies + HZ;
     add_timer(&strip_info->idle_timer);
-    if (!clear_bit(0, (void *)&strip_info->dev.tbusy))
+    if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
         printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
             strip_info->dev.name);
 }
@@ -1745,7 +1745,7 @@
         printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
         return(1);
     }
-    if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+    if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
     del_timer(&strip_info->idle_timer);
 
     /* See if someone has been ifconfigging */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.36/linux/drivers/net/sunhme.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sunhme.c	Mon May 12 10:35:41 1997
@@ -1898,7 +1898,7 @@
 		}
 	}
 
-	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("happy meal: Transmitter access conflict.\n");
 		return 1;
 	}
@@ -1955,7 +1955,7 @@
 		return 0;
 	}
 
-	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("happy meal: Transmitter access conflict.\n");
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.36/linux/drivers/net/sunlance.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sunlance.c	Mon May 12 10:35:41 1997
@@ -800,7 +800,7 @@
 	}
 
 	/* Block a timer-based transmit from overlapping. */
-	if (set_bit (0, (void *) &dev->tbusy) != 0) {
+	if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
 		printk ("Transmitter access conflict.\n");
 		return -1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.36/linux/drivers/net/sunqe.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/sunqe.c	Mon May 12 10:35:41 1997
@@ -720,7 +720,7 @@
 	if(dev->tbusy)
 		return 1;
 
-	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
@@ -762,7 +762,7 @@
 	if(dev->tbusy)
 		return 1;
 
-	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.1.36/linux/drivers/net/tulip.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/tulip.c	Mon May 12 10:35:41 1997
@@ -863,7 +863,7 @@
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	   If this ever occurs the queue layer is doing something evil! */
-	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.36/linux/drivers/net/wavelan.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/wavelan.c	Mon May 12 10:35:41 1997
@@ -64,8 +64,8 @@
 /*
  * Translate PSA irq parameter to irq number 
  */
-static int
-wv_psa_to_irq(u_char	irqval)
+__initfunc(static int
+wv_psa_to_irq(u_char	irqval))
 {
   int	irq;
 
@@ -895,7 +895,7 @@
   net_local *	lp = (net_local *)dev->priv;
 
   /* Check if we can do it now ! */
-  if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0))
+  if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
     {
       lp->reconfig_82586 = 1;
 #ifdef DEBUG_CONFIG_INFO
@@ -2799,7 +2799,7 @@
    * Block a timer-based transmit from overlapping.
    * In other words, prevent reentering this routine.
    */
-  if(set_bit(0, (void *)&dev->tbusy) != 0)
+  if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
 #ifdef DEBUG_TX_ERROR
     printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
 #endif
@@ -3999,8 +3999,8 @@
  * device structure
  * (called by wavelan_probe() & via init_module())
  */
-static int
-wavelan_config(device *	dev)
+__initfunc(static int
+wavelan_config(device *	dev))
 {
   u_long	ioaddr = dev->base_addr;
   u_char	irq_mask;
@@ -4112,11 +4112,9 @@
  * the initial value of dev->base_addr.
  * We follow the example in drivers/net/ne.c.)
  * (called in "Space.c")
- * As this function is called outside the wavelan module, it should be
- * declared extern, but it seem to cause troubles...
  */
-/* extern */ int
-wavelan_probe(device *	dev)
+__initfunc(int
+wavelan_probe(device *	dev))
 {
   short		base_addr;
   mac_addr	mac;		/* Mac address (check wavelan existence) */
diff -u --recursive --new-file v2.1.36/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.1.36/linux/drivers/net/wavelan.p.h	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/wavelan.p.h	Mon May 12 10:35:41 1997
@@ -305,6 +305,7 @@
 #include	<linux/skbuff.h>
 #include	<linux/malloc.h>
 #include	<linux/timer.h>
+#include	<linux/init.h>
 
 #include <linux/wireless.h>		/* Wireless extensions */
 
diff -u --recursive --new-file v2.1.36/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c
--- v2.1.36/linux/drivers/net/x25_asy.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/x25_asy.c	Mon May 12 10:35:41 1997
@@ -59,7 +59,7 @@
 		if (slp == NULL)
 			break;
 		/* Not in use ? */
-		if (!set_bit(SLF_INUSE, &slp->ctrl.flags))
+		if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
 			break;
 	}
 	/* SLP is set.. */
@@ -124,7 +124,7 @@
 	}
 	sl->xbuff = NULL;
 
-	if (!clear_bit(SLF_INUSE, &sl->flags)) {
+	if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
 		printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
 	}
 }
@@ -201,7 +201,7 @@
 
 static inline void x25_asy_lock(struct x25_asy *sl)
 {
-	if (set_bit(0, (void *) &sl->dev->tbusy))
+	if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
 		printk("%s: trying to lock already locked device!\n", sl->dev->name);
 }
 
@@ -210,7 +210,7 @@
 
 static inline void x25_asy_unlock(struct x25_asy *sl)
 {
-	if (!clear_bit(0, (void *)&sl->dev->tbusy))
+	if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
 		printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
 }
 
@@ -587,7 +587,7 @@
 	/* Read the characters out of the buffer */
 	while (count--) {
 		if (fp && *fp++) {
-			if (!set_bit(SLF_ERROR, &sl->flags))  {
+			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {
 				sl->rx_errors++;
 			}
 			cp++;
@@ -736,7 +736,7 @@
 	switch(s) 
 	{
 		case X25_END:
-			if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  
+			if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  
 			{
 				x25_asy_bump(sl);
 			}
@@ -750,7 +750,7 @@
 			
 		case X25_ESCAPE(X25_ESC):
 		case X25_ESCAPE(X25_END):
-			if (clear_bit(SLF_ESCAPE, &sl->flags))
+			if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
 				s = X25_UNESCAPE(s);
 			break;
 	}
diff -u --recursive --new-file v2.1.36/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.1.36/linux/drivers/net/znet.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/znet.c	Mon May 12 10:35:41 1997
@@ -351,7 +351,7 @@
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
diff -u --recursive --new-file v2.1.36/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.36/linux/drivers/pci/pci.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/pci/pci.c	Mon May 12 10:35:42 1997
@@ -13,6 +13,7 @@
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 
@@ -576,8 +577,8 @@
 /*
  * Turn on/off PCI bridge optimization. This should allow benchmarking.
  */
-static void burst_bridge(unsigned char bus, unsigned char devfn,
-			 unsigned char pos, int turn_on)
+__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn,
+				    unsigned char pos, int turn_on))
 {
 #ifdef CONFIG_PCI_OPTIMIZE
 	struct bridge_mapping_type *bmap;
@@ -791,7 +792,7 @@
  * pci_malloc() returns initialized memory of size SIZE.  Can be
  * used only while pci_init() is active.
  */
-static void *pci_malloc(long size, unsigned long *mem_startp)
+__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp))
 {
 	void *mem;
 
@@ -805,7 +806,7 @@
 }
 
 
-static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
+__initfunc(static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp))
 {
 	unsigned int devfn, l, max;
 	unsigned char cmd, tmp, hdr_type = 0;
@@ -980,12 +981,12 @@
 }
 
 
-unsigned long pci_init (unsigned long mem_start, unsigned long mem_end)
+__initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_end))
 {
 	mem_start = pcibios_init(mem_start, mem_end);
 
 	if (!pcibios_present()) {
-		printk("pci_init: no BIOS32 detected\n");
+		printk("pci_init: no PCI BIOS detected\n");
 		return mem_start;
 	}
 
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c
--- v2.1.36/linux/drivers/sbus/audio/amd7930.c	Mon Mar 17 14:54:27 1997
+++ linux/drivers/sbus/audio/amd7930.c	Mon May 12 10:35:42 1997
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.1.36/linux/drivers/sbus/audio/cs4231.c	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/audio/cs4231.c	Mon May 12 10:35:42 1997
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c
--- v2.1.36/linux/drivers/sbus/char/creator.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/creator.c	Mon May 12 10:35:42 1997
@@ -47,52 +47,3 @@
         fb->unblank = 0;
         fb->type.fb_depth = 8;
 }
-/*
- * creator.c: Linux/Sun Ultra Creator console support.
- *
- * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
- *
- */
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/proc_fs.h>
-
-#include <asm/sbus.h>
-#include <asm/io.h>
-#include <asm/fbio.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
-#include "fb.h"
-
-__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
-{
-        uint bases [2];
-        unsigned long *p;
-
-        if (!creator) {
-                prom_getproperty (con_node, "address", (char *) &bases[0], 4);
-                prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
-                p = (unsigned long *) creator = bases[0];
-                fb->base = creator;
-                fb->base = 0xff168000;
-        }
-
-        fb->type.fb_cmsize = 256;
-        fb->mmap =  0;
-        fb->loadcmap = 0;
-        fb->setcursor = 0;
-        fb->setcursormap = 0;
-        fb->setcurshape = 0;
-        fb->ioctl = 0;
-        fb->switch_from_graph = 0;
-        fb->postsetup = sun_cg_postsetup;
-        fb->reset = 0;
-        fb->blank = 0;
-        fb->unblank = 0;
-        fb->type.fb_depth = 8;
-}
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.1.36/linux/drivers/sbus/char/sunkbd.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/sunkbd.c	Mon May 12 17:39:50 1997
@@ -487,7 +487,7 @@
 				add_timer (&auto_repeat_timer);
 			}
 		}
-		rep = set_bit(keycode, key_down);
+		rep = test_and_set_bit(keycode, key_down);
 	}
 
 	if(raw_mode)
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.1.36/linux/drivers/sbus/char/sunserial.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/sunserial.c	Mon May 12 17:39:50 1997
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.38 1997/04/14 17:05:00 jj Exp $
+/* $Id: sunserial.c,v 1.39 1997/04/23 07:45:26 ecd Exp $
  * serial.c: Serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -687,7 +687,7 @@
 	if (!tty)
 		return;
 
-	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
 		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 		    tty->ldisc.write_wakeup)
 			(tty->ldisc.write_wakeup)(tty);
@@ -866,10 +866,10 @@
 	i = cflag & CBAUD;
 	if (cflag & CBAUDEX) {
 		i &= ~CBAUDEX;
-		if (i != 1)
+		if (i != 5)
 			info->tty->termios->c_cflag &= ~CBAUDEX;
 		else
-			i += 15;
+			i = 16;
 	}
 	if (i == 15) {
 		if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
@@ -1857,7 +1857,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.38 $";
+	char *revision = "$Revision: 1.39 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc.h linux/drivers/sbus/char/vfc.h
--- v2.1.36/linux/drivers/sbus/char/vfc.h	Mon Apr 14 16:28:14 1997
+++ linux/drivers/sbus/char/vfc.h	Mon May 12 10:35:42 1997
@@ -157,10 +157,16 @@
 
 #define VFC_STATUS_CAPTURE    0x08000000
 
-#ifdef VFC_DEBUG
-#define VFC_DEBUG_PRINTK(a) printk a
+#ifdef VFC_IOCTL_DEBUG
+#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
 #else
-#define VFC_DEBUG_PRINTK(a)
+#define VFC_IOCTL_DEBUG_PRINTK(a)
+#endif
+
+#ifdef VFC_I2C_DEBUG
+#define VFC_I2C_DEBUG_PRINTK(a) printk a
+#else
+#define VFC_I2C_DEBUG_PRINTK(a)
 #endif
 
 #endif /* _LINUX_VFC_H_ */
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.36/linux/drivers/sbus/char/vfc_dev.c	Mon Apr 14 16:28:14 1997
+++ linux/drivers/sbus/char/vfc_dev.c	Mon May 12 10:35:42 1997
@@ -3,11 +3,11 @@
  *
  * Driver for the Videopix Frame Grabber.
  * 
- * In order to use the VFC you need to progeam the video controller
+ * In order to use the VFC you need to program the video controller
  * chip. This chip is the Phillips SAA9051.  You need to call their
  * documentation ordering line to get the docs.
  *
- * Their is very little documentation on the VFC itself.  There is
+ * There is very little documentation on the VFC itself.  There is
  * some useful info that can be found in the manuals that come with
  * the card.  I will hopefully write some better docs at a later date.
  *
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/uaccess.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -30,12 +31,11 @@
 #include <asm/delay.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/uaccess.h>
 
 #define VFC_MAJOR (60)
 
 #if 0
-#define VFC_DEBUG
+#define VFC_IOCTL_DEBUG
 #endif
 
 #include "vfc.h"
@@ -133,30 +133,27 @@
 	dev->control_reg=0;
 	dev->poll_wait=NULL;
 	dev->busy=0;
-	/* initialize the timer struct */
 	return 0;
 }
 
 int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev,
 		    int instance) {
-	struct linux_prom_registers reg;
 	if(!dev) {
 		printk(KERN_ERR "VFC: Bogus pointer passed\n");
 		return -ENOMEM;
 	}
 	printk("Initializing vfc%d\n",instance);
 	dev->regs=NULL;
-	memcpy(&reg,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers));
-	prom_apply_sbus_ranges(sdev->my_bus, &reg, sdev->num_registers, sdev);
-	dev->regs=sparc_alloc_io(reg.phys_addr, 0,
+	prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev);
+	dev->regs=sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
 				 sizeof(struct vfc_regs), vfcstr, 
-				 reg.which_io, 0x0);
-	dev->which_io=reg.which_io;
-	dev->phys_regs=(struct vfc_regs *)reg.phys_addr;
+				 sdev->reg_addrs[0].which_io, 0x0);
+	dev->which_io=sdev->reg_addrs[0].which_io;
+	dev->phys_regs=(struct vfc_regs *)sdev->reg_addrs[0].phys_addr;
 	if(!dev->regs) return -EIO;
 
 	printk("vfc%d: registers mapped at phys_addr: 0x%lx\n    virt_addr: 0x%lx\n",
-	       instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs);
+	       instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
 
 	if(init_vfc_devstruct(dev,instance)) return -EINVAL;
 	if(init_vfc_hw(dev)) return -EIO;
@@ -191,52 +188,58 @@
 	return 0;
 }
 
-static int vfc_release(struct inode *inode,struct file *file) 
+static void vfc_release(struct inode *inode,struct file *file) 
 {
 	struct vfc_dev *dev;
 	dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
-	if(!dev) return -EINVAL;
-	if(!dev->busy) return 0;
+	if(!dev) return;
+	if(!dev->busy) return;
 	dev->busy=0;
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return;
 }
 
 static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) 
 {
 	struct vfc_debug_inout inout;
 	unsigned char *buffer;
+	int ret;
+
+	if(!suser()) return -EPERM;
 
 	switch(cmd) {
 	case VFC_I2C_SEND:
-		if(copy_from_user(&inout, (void *)arg, sizeof(inout))) 
+		if(copy_from_user(&inout, (void *)arg, sizeof(inout))) {
 			return -EFAULT;
+		}
 
 		buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL);
 		if (!buffer)
 			return -ENOMEM;
-		if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) {
-			kfree_s(buffer,inout.len);
+
+		if(copy_from_user(buffer, inout.buffer, 
+				  inout.len*sizeof(char));) {
+			kfree_s(buffer,inout.len*sizeof(char));
 			return -EFAULT;
 		}
+		
 
 		vfc_lock_device(dev);
 		inout.ret=
 			vfc_i2c_sendbuf(dev,inout.addr & 0xff,
 					inout.buffer,inout.len);
-		if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
-			kfree_s(buffer,inout.len);
+
+		if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
+			kfree_s(buffer, inout.len);
 			return -EFAULT;
 		}
 		vfc_unlock_device(dev);
 
-		kfree_s(buffer, inout.len);
-
 		break;
 	case VFC_I2C_RECV:
-
-		if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+		if (copy_from_user(&inout, (void *)arg, sizeof(inout))) {
 			return -EFAULT;
+		}
 
 		buffer = kmalloc(inout.len, GFP_KERNEL);
 		if (!buffer)
@@ -248,11 +251,11 @@
 					,buffer,inout.len);
 		vfc_unlock_device(dev);
 		
-		if(copy_to_user(inout.buffer, buffer, inout.len)) {
+		if (copy_to_user(inout.buffer, buffer, inout.len)) {
 			kfree_s(buffer,inout.len);
 			return -EFAULT;
 		}
-		if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+		if (copy_to_user((void *)arg,&inout,sizeof(inout))) {
 			kfree_s(buffer,inout.len);
 			return -EFAULT;
 		}
@@ -306,12 +309,10 @@
 			  struct vfc_dev *dev, unsigned long arg) 
 {
 	int setcmd,ret=0;
-	if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
+	if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
 		return -EFAULT;
-#if 0
-	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
-			  dev->instance,setcmd));
-#endif
+	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
+				dev->instance,setcmd));
 	switch(setcmd) {
 	case MEMPRST:
 		vfc_lock_device(dev);
@@ -359,13 +360,14 @@
 {
 	int ret=0;
 	int cmd;
+
 	if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
-		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
 				  "vfc_port_change_ioctl\n",dev->instance));
 		return -EFAULT;
 	}
 	
-	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
+	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
 			  dev->instance,cmd));
 
 	switch(cmd) {
@@ -424,12 +426,12 @@
 	int ret=0;
 	int cmd;
 	if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
-		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
 				  "vfc_set_video_ioctl\n",dev->instance));
-		return -EFAULT;
+		return ret;
 	}
 	
-	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
+	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
 			  dev->instance,cmd));
 	switch(cmd) {
 
@@ -490,12 +492,12 @@
 		else
 			status=PAL_NOCOLOR;
 	}
-	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
+	VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
 			  status,buf[0]));
-	if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
-		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+	if (copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
 				 "vfc_get_video_ioctl\n",dev->instance));
-		return -EFAULT;
+		return ret;
 	}
 	return ret;
 }
@@ -513,11 +515,13 @@
 	switch(cmd & 0x0000ffff) {
 	case VFCGCTRL:
 #if 0
-		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
 #endif
 		tmp=dev->regs->control;
-		if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int)))
-			return -EFAULT;
+		if(copy_to_user((void *)arg,&tmp, sizeof(unsigned int))) {
+			ret=-EFAULT;
+			break;
+		}
 		ret=0;
 		break;
 	case VFCSCTRL:
@@ -530,12 +534,9 @@
 		ret=vfc_set_video_ioctl(inode,file,dev,arg);
 		break;
 	case VFCHUE:
-#if 0
-		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
-#endif
-
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
 		if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) {
-			VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
+			VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
 					  "to IOCTL(VFCHUE)",dev->instance));
 			ret=-EFAULT;
 		} else {
@@ -549,7 +550,7 @@
 		break;
 	case VFCRDINFO:
 		ret=-EINVAL;
-		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
+		VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
 		break;
 	default:
 		ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)),
@@ -584,8 +585,9 @@
 	return 0;
 }
 
-static long long vfc_lseek(struct inode *inode, struct file *file, 
-	      long long offset, int origin) 
+
+static int vfc_lseek(struct inode *inode, struct file *file, 
+	      off_t offset, int origin) 
 {
 	return -ESPIPE;
 }
@@ -595,13 +597,12 @@
 	NULL,        /* vfc_write */
 	NULL,        /* vfc_read */
 	NULL,        /* vfc_readdir */
-	NULL,        /* vfc_poll */
+	NULL,        /* vfc_select */
 	vfc_ioctl,   
 	vfc_mmap, 
 	vfc_open,
 	vfc_release,
 };
-
 
 static int vfc_probe(void)
 {
diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c
--- v2.1.36/linux/drivers/sbus/char/vfc_i2c.c	Mon Apr 14 16:28:14 1997
+++ linux/drivers/sbus/char/vfc_i2c.c	Mon May 12 10:35:42 1997
@@ -31,8 +31,8 @@
 #include <asm/system.h>
 #include <asm/sbus.h>
 
-#if 0
-#define VFC_DEBUG
+#if 0 
+#define VFC_I2C_DEBUG
 #endif
 
 #include "vfc.h"
@@ -72,6 +72,8 @@
 
 void vfc_i2c_delay_wakeup(struct vfc_dev *dev) 
 {
+	/* Used to profile code and eliminate too many delays */
+	VFC_I2C_DEBUG_PRINTK(("vfc%d: Delaying\n",dev->instance));
 	wake_up(&dev->poll_wait);
 }
 
@@ -95,14 +97,14 @@
 
 int vfc_init_i2c_bus(struct vfc_dev *dev)
 {
-	dev->regs->i2c_s1= ENABLE_SERIAL | ACK;
+	dev->regs->i2c_s1= ENABLE_SERIAL | SELECT(S0) | ACK;
 	vfc_i2c_reset_bus(dev);
 	return 0;
 }
 
 int vfc_i2c_reset_bus(struct vfc_dev *dev) 
 {
-	VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
+	VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
 			  dev->instance));
 	if(!dev) return -EINVAL;
 	if(!dev->regs) return -EINVAL;
@@ -110,7 +112,7 @@
 	dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
 	vfc_i2c_delay(dev);
 	dev->regs->i2c_s1=CLEAR_I2C_BUS;
-	VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
+	VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
 			  dev->instance, dev->regs->i2c_s1));
 	return 0;
 }
@@ -146,7 +148,7 @@
 { 
 	int ret,raddr;
 #if 1
-	dev->regs->i2c_s1=SEND_I2C_STOP;
+	dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
 	dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL;
 	vfc_i2c_delay(dev);
 #endif
@@ -154,12 +156,12 @@
 	switch(mode) {
 	case VFC_I2C_READ:
 		dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1);
-		VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
+		VFC_I2C_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
 				  dev->instance,addr | 0x1));
 		break;
 	case VFC_I2C_WRITE:
 		dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1);
-		VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
+		VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
 				  dev->instance,addr & ~0x1));
 		break;
 	default:
@@ -215,7 +217,7 @@
 	int ret;
 	if(last) {
 		dev->regs->i2c_reg=NEGATIVE_ACK;
-		VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n",
+		VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
 				  dev->instance));
 	} else {
 		dev->regs->i2c_s1=ACK;
@@ -255,6 +257,8 @@
 			printk(KERN_ERR "vfc%d: "
 			       "VFC error while recieving byte\n",
 			       dev->instance);
+			dev->regs->i2c_s1=SEND_I2C_STOP;
+			ret=-EINVAL;
 		}
 		buf++;
 	}
@@ -286,7 +290,7 @@
 		ret=vfc_i2c_xmit_byte(dev,buf);
 		switch(ret) {
 		case XMIT_LAST_BYTE:
-			VFC_DEBUG_PRINTK(("vfc%d: "
+			VFC_I2C_DEBUG_PRINTK(("vfc%d: "
 					  "Reciever ended transmission with "
 					  " %d bytes remaining\n",
 					  dev->instance,count));
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.1.36/linux/drivers/scsi/53c7,8xx.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/scsi/53c7,8xx.c	Mon May 12 17:39:50 1997
@@ -254,7 +254,6 @@
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <linux/init.h>
-#undef current
 
 #include "scsi.h"
 #include "hosts.h"
@@ -783,7 +782,7 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     int i, j;
-    u32 *current;
+    u32 *curr;
     for (i = 0; i < 16; ++i) {
 	hostdata->request_sense[i] = 0;
     	for (j = 0; j < 8; ++j) 
@@ -792,14 +791,14 @@
     }
     hostdata->issue_queue = NULL;
     hostdata->running_list = hostdata->finished_queue = 
-	hostdata->current = NULL;
-    for (i = 0, current = (u32 *) hostdata->schedule; 
-	i < host->can_queue; ++i, current += 2) {
-	current[0] = hostdata->NOP_insn;
-	current[1] = 0xdeadbeef;
+	hostdata->curr = NULL;
+    for (i = 0, curr = (u32 *) hostdata->schedule; 
+	i < host->can_queue; ++i, curr += 2) {
+	curr[0] = hostdata->NOP_insn;
+	curr[1] = 0xdeadbeef;
     }
-    current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
-    current[1] = (u32) virt_to_bus (hostdata->script) +
+    curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+    curr[1] = (u32) virt_to_bus (hostdata->script) +
 	hostdata->E_wait_reselect;
     hostdata->reconnect_dsa_head = 0;
     hostdata->addr_reconnect_dsa_head = (u32) 
@@ -2104,7 +2103,7 @@
     int left, found;
     volatile struct NCR53c7x0_cmd * linux_search;
     volatile struct NCR53c7x0_cmd * volatile *linux_prev;
-    volatile u32 *ncr_prev, *current, ncr_search;
+    volatile u32 *ncr_prev, *curr, ncr_search;
 
 #if 0
     printk ("scsi%d: abnormal finished\n", host->host_no);
@@ -2120,13 +2119,13 @@
      */
 
 
-    for (found = 0, left = host->can_queue, current = hostdata->schedule; 
-	left > 0; --left, current += 2)
+    for (found = 0, left = host->can_queue, curr = hostdata->schedule; 
+	left > 0; --left, curr += 2)
     {
-	if (issue_to_cmd (host, hostdata, (u32 *) current) == cmd) 
+	if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd) 
 	{
-	    current[0] = hostdata->NOP_insn;
-	    current[1] = 0xdeadbeef;
+	    curr[0] = hostdata->NOP_insn;
+	    curr[1] = 0xdeadbeef;
 	    ++found;
 	    break;
 	}
@@ -3964,7 +3963,7 @@
     Scsi_Cmnd *tmp = cmd->cmd;
     unsigned long flags;
     /* dsa start is negative, so subtraction is used */
-    volatile u32 *current;
+    volatile u32 *curr;
 
     int i;
     NCR53c7x0_local_setup(host);
@@ -3991,9 +3990,9 @@
 	return;
     }
 
-    for (i = host->can_queue, current = hostdata->schedule; 
-	i > 0  && current[0] != hostdata->NOP_insn;
-	--i, current += 2 /* JUMP instructions are two words */);
+    for (i = host->can_queue, curr = hostdata->schedule; 
+	i > 0  && curr[0] != hostdata->NOP_insn;
+	--i, curr += 2 /* JUMP instructions are two words */);
 
     if (i > 0) {
 	++hostdata->busy[tmp->target][tmp->lun];
@@ -4002,13 +4001,13 @@
 
 	/* Restore this instruction to a NOP once the command starts */
 	cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
-	    sizeof(u32)] = (u32) virt_to_bus ((void *)current);
+	    sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
 	/* Replace the current jump operand.  */
-	current[1] =
+	curr[1] =
 	    virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
 	    hostdata->E_dsa_code_template;
 	/* Replace the NOP instruction with a JUMP */
-	current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+	curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
 	    DBC_TCI_TRUE;
     }  else {
 	printk ("scsi%d: no free slot\n", host->host_no);
@@ -4510,8 +4509,8 @@
 
 		    /*
 		     * NCR53c700 and NCR53c700-66 change the current SCSI
-		     * process, hostdata->current, in the Linux driver so
-		     * cmd = hostdata->current.
+		     * process, hostdata->curr, in the Linux driver so
+		     * cmd = hostdata->curr.
 		     *
 		     * With other chips, we must look through the commands
 		     * executing and find the command structure which 
@@ -4519,7 +4518,7 @@
 		     */
 
 		    if (hostdata->options & OPTION_700) {
-			cmd = (struct NCR53c7x0_cmd *) hostdata->current;
+			cmd = (struct NCR53c7x0_cmd *) hostdata->curr;
 		    } else {
 			dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
 			for (cmd = (struct NCR53c7x0_cmd *) 
@@ -5872,7 +5871,7 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     u32 *dsa, *next_dsa;
-    volatile u32 *current;
+    volatile u32 *curr;
     int left;
     Scsi_Cmnd *cmd, *next_cmd;
     unsigned long flags;
@@ -5914,11 +5913,11 @@
      */
 
     printk ("scsi%d : schedule dsa array :\n", host->host_no);
-    for (left = host->can_queue, current = hostdata->schedule;
-	    left > 0; current += 2, --left)
-	if (current[0] != hostdata->NOP_insn) 
+    for (left = host->can_queue, curr = hostdata->schedule;
+	    left > 0; curr += 2, --left)
+	if (curr[0] != hostdata->NOP_insn) 
 /* FIXME : convert pointer to dsa_begin to pointer to dsa. */
-	    print_dsa (host, bus_to_virt (current[1] - 
+	    print_dsa (host, bus_to_virt (curr[1] - 
 		(hostdata->E_dsa_code_begin - 
 		hostdata->E_dsa_code_template)), "");
     printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -6108,7 +6107,7 @@
 	host->hostdata;
     struct NCR53c7x0_cmd *c;
     int i;
-    u32 *current;
+    u32 *curr;
     Scsi_Cmnd *list = NULL, *tmp;
     for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c; 
     	c = (struct NCR53c7x0_cmd *) c->next)  {
@@ -6129,12 +6128,12 @@
     }
 
     if (free) { 
-	for (i = 0, current = (u32 *) hostdata->schedule; 
-	    i < host->can_queue; ++i, current += 2) {
-	    current[0] = hostdata->NOP_insn;
-	    current[1] = 0xdeadbeef;
+	for (i = 0, curr = (u32 *) hostdata->schedule; 
+	    i < host->can_queue; ++i, curr += 2) {
+	    curr[0] = hostdata->NOP_insn;
+	    curr[1] = 0xdeadbeef;
 	}
-	hostdata->current = NULL;
+	hostdata->curr = NULL;
     }
 
     if (issue) {
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h
--- v2.1.36/linux/drivers/scsi/53c7,8xx.h	Mon Jun  3 20:06:37 1996
+++ linux/drivers/scsi/53c7,8xx.h	Tue May 13 21:58:42 1997
@@ -1394,7 +1394,7 @@
 						/* commands running, maintained
 						   by Linux driver */
 
-    volatile struct NCR53c7x0_cmd *current;	/* currently connected 
+    volatile struct NCR53c7x0_cmd *curr;	/* currently connected 
 						   nexus, ONLY valid for
 						   NCR53c700/NCR53c700-66
 						 */
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.1.36/linux/drivers/scsi/ChangeLog.ncr53c8xx	Sun Apr 13 10:18:21 1997
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon May 12 20:45:35 1997
@@ -1,3 +1,75 @@
+Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1b
+	- Cosmetic changes.
+	- Some heavy testings under pre-linux-2.1.37-6
+
+Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1a
+	- PFEN wrongly used for PREFETCH feature bit testing.
+	  Changed to _F_PFEN.
+	- 2 SCR_COPY that need NO FLUSH bit to be removed had been missed 
+	  in tp->getscr[] script (loads SXFER and SCNTL3 on reselection).
+
+Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1
+	- Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is 
+	  possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for  
+	  my configuration (max queued command / device = 8).
+	  This option bit is removed from the script instance for chips 
+	  that donnot support prefetching.
+	- Rewrite the ncr_exception() routine more simple (I think) and 
+	  remove useless code.
+	- Change the data_in and data_out script management.
+	  Use the bottom part of these scripts instead of the beginning.
+	  That avoids to zero the scatter/gather array when a command is 
+	  queued (1k) and to deal with some weird IID on MOVE 0 bytes when 
+	  a target wants to transfer more bytes than expected.
+	- Misc. improvements in the init code.
+	- Remove IOMAPPED/MMIO automatic switching option.
+	  Was useless and reported not reliable.
+	- Fix a double read of DSTAT and remove DFE testing in the 
+	  Phase mismatch service routine.
+	- Etc...
+
+Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.0a
+	- Add support if the Diamond FirePort 40 (SYM53C875J chip)
+
+Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.0
+	- incorporate __initdata and __initfunc directives in order to 
+	  allow 'init' to free unused memory after driver initialisations.
+	  Patch sent by Roberto Fichera.
+	- rewrite the init code of the driver. Now a feature descriptor 
+	  is used for each real chip types. The code is a lot more clean,
+	  since the driver uses device and revision ids only in the 
+	  detection procedure.
+	- add 'pcifix' boot command line. This command allows to fix up PCI 
+	  config space for new chips which support features based on the 
+	  cache line size and 'write and invalidate'.
+	- incorporate in the driver, the code used for error recovery  
+	  testing. This code is normally not compiled; have to define 
+	  SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it.
+	- take into account actual SCSI bus mode for 53C895 LVD/SE controller.
+	  In single ended mode only fast20 is supported.
+          (Just to not be late since such controllers are not yet available)
+          
+
+Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18f
+	- fix an old bug included in the initial port (version 0.0).
+	  The driver allocated 10 bytes of static data and uses 12 bytes.
+	  No danger, since data are generally aligned on 4 bytes boundary 
+	  and so byte 10 and 11 are free (I hope ...)
+
+Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18e
+	- reset all when an unexpected data cycle is detected while 
+	  disconnecting.
+	- make changes to abort() ans reset() functions according to 
+	  Leonard's documentation.
+	- small fix in some message for hard errors.
+
 Sat Apr 5  13:00 1997 Gerard Roudier (groudier@club-internet.fr)
 	* revision 1.18d
 	- Probe NCR pci device ids in reverse order if asked by user from 
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.36/linux/drivers/scsi/Config.in	Mon Apr 14 16:28:15 1997
+++ linux/drivers/scsi/Config.in	Mon May 12 10:35:42 1997
@@ -86,6 +86,9 @@
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
+  dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+fi
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
   if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.36/linux/drivers/scsi/Makefile	Mon Apr 14 16:28:15 1997
+++ linux/drivers/scsi/Makefile	Mon May 12 10:35:42 1997
@@ -185,6 +185,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_DC390T),y)
+L_OBJS += tmscsim.o
+else
+  ifeq ($(CONFIG_SCSI_DC390T),m)
+  M_OBJS += tmscsim.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_AM53C974),y)
 L_OBJS += AM53C974.o
 else
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.1.36/linux/drivers/scsi/README.ncr53c8xx	Sun Apr 13 10:18:21 1997
+++ linux/drivers/scsi/README.ncr53c8xx	Mon May 12 20:45:35 1997
@@ -1,10 +1,10 @@
-The linux NCR53C8XX driver README file
+The Linux NCR53C8XX driver README file
 
 Written by Gerard Roudier <groudier@club-internet.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-6 April 1997
+9 May 1997
 ===============================================================================
 
 1.  Introduction
@@ -22,6 +22,7 @@
       8.5  Set debug mode
       8.6  Clear profile counters
       8.7  Set flag (no_sync)
+      8.8  Debug error recovery
 9.  Configuration parameters
 10. Boot setup commands
       10.1 Syntax
@@ -203,7 +204,6 @@
   IO port address 0x6000, IRQ number 10
   Using memory mapped IO at virtual address 0x282c000
   Synchronous transfer period 25, max commands per lun 4
-
 Profiling information:
   num_trans    = 18014
   num_kbytes   = 671314
@@ -390,6 +390,57 @@
     - setflag all
       will allow disconnection for all devices on the SCSI bus.
 
+
+8.8 Debug error recovery
+
+    debug_error_recovery <error to trigger>
+
+    Available error type to trigger:
+        sge:     SCSI gross error
+        abort:   abort command from the middle-level driver
+        reset:   reset command from the middle-level driver
+        parity:  scsi parity detected in DATA IN phase
+        none:    restore driver normal behaviour
+
+    The code corresponding to this feature is normally not compiled.
+    Its purpose is driver testing only. In order to compile the code 
+    that allows to trigger error recovery you must define at compile time 
+    SCSI_NCR_DEBUG_ERROR_RECOVERY.
+    If you have compiled the driver with this option, nothing will happen 
+    as long as you donnot use the control command 'debug_error_recovery' 
+    with sge, abort, reset or parity as argument.
+    If you select an error type, it will be triggered by the driver every 
+    30 seconds.
+
+8.9 PCI configuration fix-up
+
+    pcifix <option bits>
+
+    Available option bits:
+        0x1:     Set PCI cache-line size register if not set.
+        0x2:     Set write and invalidate bit in PCI command register.
+
+    Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+
+    These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875 
+    and are only supported for Pentium and 486 class processors.
+    Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple 
+    and PCI write and invalidate commands. These features require the 
+    cache line size register to be properly set in the PCI configuration 
+    space of the chips. On the other hand, chips will use PCI write and 
+    invalidate commands only if the corresponding bit is set to 1 in the 
+    PCI command register.
+
+    Not all PCI bioses set the PCI cache line register and the PCI write and 
+    invalidate bit in the PCI configuration space of 53C8XX chips.
+    Optimized PCI accesses may be broken for some PCI/memory controllers or 
+    make problems with some PCI boards.
+
+    This fix-up works flawlessly on my system.
+    (MB Triton HX / 53C875 / 53C810A)
+    I use these options at my own risks as you will do if you decide to 
+    use them too.
+
 9. Configuration parameters
 
 If the firmware of all your devices is perfect enough, all the
@@ -736,9 +787,9 @@
 
 You must untar the distribution with the following command:
 
-	tar zxvf ncrBsd2Linux-1.18d-src.tar.gz
+	tar zxvf ncrBsd2Linux-2.1b-src.tar.gz
 
-The sub-directory ncr53c8xx-1.18d will be created. Change to this directory.
+The sub-directory ncr53c8xx-2.1b will be created. Change to this directory.
 
 
 12.2 Installation procedure
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v2.1.36/linux/drivers/scsi/a2091.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/scsi/a2091.c	Mon May 12 10:35:42 1997
@@ -3,6 +3,7 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/version.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -190,7 +191,7 @@
 
 static int num_a2091 = 0;
 
-int a2091_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a2091_detect(Scsi_Host_Template *tpnt))
 {
     static unsigned char called = 0;
     struct Scsi_Host *instance;
@@ -243,13 +244,11 @@
 int a2091_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-DMA(instance)->CNTR = 0;
-zorro_unconfig_board(instance->unique_id, 0);
-if (--num_a2091 == 0)
-  free_irq(IRQ_AMIGA_PORTS, a2091_intr);
-wd33c93_release();
+	DMA(instance)->CNTR = 0;
+	zorro_unconfig_board(instance->unique_id, 0);
+	if (--num_a2091 == 0)
+		free_irq(IRQ_AMIGA_PORTS, a2091_intr);
+	wd33c93_release();
 #endif
-return 1;
+	return 1;
 }
-
-
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v2.1.36/linux/drivers/scsi/a3000.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/scsi/a3000.c	Mon May 12 10:35:42 1997
@@ -3,6 +3,7 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/version.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -166,7 +167,7 @@
     }
 }
 
-int a3000_detect(Scsi_Host_Template *tpnt)
+__initfunc(int a3000_detect(Scsi_Host_Template *tpnt))
 {
     static unsigned char called = 0;
 
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- v2.1.36/linux/drivers/scsi/atari_NCR5380.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/atari_NCR5380.c	Mon May 12 10:35:42 1997
@@ -323,7 +323,7 @@
 static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
 
 
-static void init_tags( void )
+__initfunc(static void init_tags( void ))
 {
     int target, lun;
     TAG_ALLOC *ta;
@@ -665,7 +665,7 @@
 }
 
 
-static void NCR5380_all_init (void)
+static inline void NCR5380_all_init (void)
 {
     static int done = 0;
     if (!done) {
@@ -684,7 +684,7 @@
  * Inputs : instance, pointer to this instance.  Unused.
  */
 
-static void NCR5380_print_options (struct Scsi_Host *instance)
+__initfunc(static void NCR5380_print_options (struct Scsi_Host *instance))
 {
     printk(" generic options"
 #ifdef AUTOSENSE 
@@ -848,7 +848,7 @@
  * 
  */
 
-static void NCR5380_init (struct Scsi_Host *instance, int flags)
+__initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags))
 {
     int i;
     SETUP_HOSTDATA(instance);
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.1.36/linux/drivers/scsi/atari_scsi.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/atari_scsi.c	Mon May 12 10:35:42 1997
@@ -89,6 +89,7 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/atarihw.h>
@@ -765,7 +766,7 @@
 }
 #endif
 
-void atari_scsi_setup( char *str, int *ints )
+__initfunc(void atari_scsi_setup( char *str, int *ints ))
 {
 	/* Format of atascsi parameter is:
 	 *   atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
@@ -869,7 +870,7 @@
 }
 
 	
-static void atari_scsi_reset_boot( void )
+__initfunc(static void atari_scsi_reset_boot( void ))
 {
 	unsigned long end;
 	
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h
--- v2.1.36/linux/drivers/scsi/dc390.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/dc390.h	Tue May 13 21:58:42 1997
@@ -0,0 +1,147 @@
+/***********************************************************************
+ *	FILE NAME : DC390.H					       *
+ *	     BY   : C.L. Huang					       *
+ *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
+ *		     Bus Master Host Adapter			       *
+ ***********************************************************************/
+
+/* Kernel version autodetection */
+
+#include <linux/version.h>
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50)
+#define VERSION_ELF_1_2_13
+#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95)
+#define VERSION_1_3_85
+#else
+#define VERSION_2_0_0
+#endif
+
+/*
+ * AMD 53C974 driver, header file
+ */
+
+#ifndef DC390_H
+#define DC390_H
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#ifdef	VERSION_2_0_0
+#include <scsi/scsicam.h>
+#else
+#include <linux/scsicam.h>
+#endif
+
+extern int DC390_detect(Scsi_Host_Template *psht);
+extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+extern int DC390_abort(Scsi_Cmnd *cmd);
+
+#ifdef	VERSION_2_0_0
+extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
+#else
+extern int DC390_reset(Scsi_Cmnd *cmd);
+#endif
+
+#ifdef	VERSION_ELF_1_2_13
+extern int DC390_bios_param(Disk *disk, int devno, int geom[]);
+#else
+extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
+#endif
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *);
+#else
+#define DC390_release NULL
+#endif
+
+#ifndef VERSION_ELF_1_2_13
+extern struct proc_dir_entry proc_scsi_tmscsim;
+extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+#endif
+
+#ifdef	VERSION_2_0_0
+
+#define DC390_T    {			\
+	NULL,	/* *next */		\
+	NULL,	/* *usage_count */	\
+	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
+	tmscsim_proc_info,	/* (*proc_info)() */	\
+	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	DC390_detect,			\
+	DC390_release,	/* (*release)() */	\
+	NULL,	/* *(*info)() */	\
+	NULL,	/* (*command)() */	\
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	SG_ALL, 		\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+
+#ifdef	VERSION_1_3_85
+
+#define DC390_T    {			\
+	NULL,	/* *next */		\
+	NULL,	/* *usage_count */	\
+	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
+	tmscsim_proc_info,	/* (*proc_info)() */	\
+	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	DC390_detect,			\
+	DC390_release,	/* (*release)() */	\
+	NULL,	/* *(*info)() */	\
+	NULL,	/* (*command)() */	\
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	SG_ALL, 		\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+
+#ifdef	VERSION_ELF_1_2_13
+
+#define DC390_T     {		\
+	NULL,			\
+	NULL,			\
+	"Tekram DC390(T) V1.10 Dec-05-1996",\
+	DC390_detect,		\
+	DC390_release,			\
+	NULL, /* info */	\
+	NULL, /* command, deprecated */ \
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	16,/* old (SG_ALL) */	\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#endif /* DC390_H */
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v2.1.36/linux/drivers/scsi/gvp11.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/gvp11.c	Mon May 12 10:35:42 1997
@@ -3,6 +3,7 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/version.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -198,7 +199,7 @@
 
 static int num_gvp11 = 0;
 
-int gvp11_detect(Scsi_Host_Template *tpnt)
+__initfunc(int gvp11_detect(Scsi_Host_Template *tpnt))
 {
     static unsigned char called = 0;
     struct Scsi_Host *instance;
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.36/linux/drivers/scsi/hosts.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/hosts.c	Mon May 12 10:35:42 1997
@@ -158,6 +158,10 @@
 #include "NCR53c406a.h"
 #endif
 
+#ifdef CONFIG_SCSI_DC390T
+#include "dc390.h"
+#endif
+
 #ifdef CONFIG_SCSI_AM53C974
 #include "AM53C974.h"
 #endif
@@ -309,6 +313,9 @@
 #endif
 #ifdef CONFIG_SCSI_EATA
     EATA,
+#endif
+#ifdef CONFIG_SCSI_DC390T
+    DC390_T,
 #endif
 #ifdef CONFIG_SCSI_AM53C974
     AM53C974,
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.1.36/linux/drivers/scsi/ide-scsi.c	Sun Jan 26 02:07:18 1997
+++ linux/drivers/scsi/ide-scsi.c	Mon May 12 17:39:50 1997
@@ -242,7 +242,7 @@
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
-	if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.36/linux/drivers/scsi/ncr53c8xx.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/ncr53c8xx.c	Mon May 12 20:45:35 1997
@@ -40,7 +40,7 @@
 */
 
 /*
-**	16 April 1997, version 1.18e
+**	9 May 1997, version 2.1b
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -56,7 +56,7 @@
 **		53C820		(Wide, NCR BIOS in flash bios required)
 **		53C825		(Wide, ~53C820 with on board rom BIOS)
 **		53C860		(Narrow fast 20, BIOS required)
-**		53C875		(Wide fast 40 with on board rom BIOS)
+**		53C875		(Wide fast 20 with on board rom BIOS)
 **		53C895		(Ultra2 80 MB/s with on board rom BIOS)
 **
 **	Other features:
@@ -65,7 +65,6 @@
 **		Shared IRQ (since linux-1.3.72)
 */
 
-#define SCSI_NCR_DEBUG
 #define SCSI_NCR_DEBUG_FLAGS	(0)		
 
 #define NCR_DATE "pl24 96/12/14"
@@ -111,6 +110,17 @@
 #include "../block/blk.h"
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
+#include <linux/init.h>
+#else
+#ifndef	__initdata
+#define	__initdata
+#endif
+#ifndef	__initfunc
+#define	__initfunc(__arginit) __arginit
+#endif
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "constants.h"
@@ -133,15 +143,6 @@
 */
 
 /*
-**	Proc info and user command support
-*/
-
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#define SCSI_NCR_PROFILE
-#define SCSI_NCR_USER_COMMAND
-#endif
-
-/*
 **    SCSI address of this device.
 **    The boot routines should have set it.
 **    If not, use this.
@@ -212,8 +213,6 @@
 
 #if defined(SCSI_NCR_IOMAPPED)
 #define NCR_IOMAPPED
-#else
-#define NCR_MEMORYMAPPED
 #endif
 
 /*
@@ -292,6 +291,7 @@
 
 	return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
 }
+
 static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size)
 {
 	if (vaddr)
@@ -422,6 +422,8 @@
 **	Head of list of NCR boards
 **
 **	Host is retrieved by its irq level.
+**	If interrupts are shared, the internal host control block 
+**	address (struct ncb) is used as device id.
 */
 
 static struct Scsi_Host		*first_host	= NULL;
@@ -470,6 +472,7 @@
 	unsigned ultra_scsi	: 2;
 	unsigned force_sync_nego: 1;
 	unsigned reverse_probe: 1;
+	unsigned pci_fix_up: 2;
 	u_char	verbose;
 	u_char	default_tags;
 	u_short	default_sync;
@@ -482,8 +485,13 @@
 	u_char	irqm;
 };
 
-static struct ncr_driver_setup driver_setup	= SCSI_NCR_DRIVER_SETUP;
-static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP;
+static struct ncr_driver_setup
+	driver_setup			= SCSI_NCR_DRIVER_SETUP;
+
+#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
 
 /*
 **	Other Linux definitions
@@ -531,7 +539,7 @@
 **    Can be changed at runtime too.
 */
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	#define DEBUG_FLAGS ncr_debug
 #else
 	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
@@ -569,37 +577,37 @@
 */
 
 /*
-**	IO mapped input / ouput
+**	IO mapped only input / ouput
 */
 
-#define	IOM_INB(r)         inb (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INB_OFF(o)     inb (np->port + (o))
-#define	IOM_INW(r)         inw (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL(r)         inl (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL_OFF(o)     inl (np->port + (o))
-
-#define	IOM_OUTB(r, val)     outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTW(r, val)     outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL(r, val)     outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
+#define	IOM_INB(r)		inb (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INB_OFF(o)		inb (np->port + (o))
+#define	IOM_INW(r)		inw (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INL(r)		inl (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INL_OFF(o)		inl (np->port + (o))
+
+#define	IOM_OUTB(r, val)	outb ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTW(r, val)	outw ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTL(r, val)	outl ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTL_OFF(o, val)	outl ((val), np->port + (o))
 
 /*
 **	MEMORY mapped IO input / output
 */
 
-#define MMIO_INB(r)        readb(&np->reg->r)
-#define MMIO_INB_OFF(o)    readb((char *)np->reg + (o))
-#define MMIO_INW(r)        readw(&np->reg->r)
-#define MMIO_INL(r)        readl(&np->reg->r)
-#define MMIO_INL_OFF(o)    readl((char *)np->reg + (o))
-
-#define MMIO_OUTB(r, val)     writeb((val), &np->reg->r)
-#define MMIO_OUTW(r, val)     writew((val), &np->reg->r)
-#define MMIO_OUTL(r, val)     writel((val), &np->reg->r)
-#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg + (o))
+#define MMIO_INB(r)		readb(&np->reg->r)
+#define MMIO_INB_OFF(o)		readb((char *)np->reg + (o))
+#define MMIO_INW(r)		readw(&np->reg->r)
+#define MMIO_INL(r)		readl(&np->reg->r)
+#define MMIO_INL_OFF(o)		readl((char *)np->reg + (o))
+
+#define MMIO_OUTB(r, val)	writeb((val), &np->reg->r)
+#define MMIO_OUTW(r, val)	writew((val), &np->reg->r)
+#define MMIO_OUTL(r, val)	writel((val), &np->reg->r)
+#define MMIO_OUTL_OFF(o, val)	writel((val), (char *)np->reg + (o))
 
 /*
-**	IO mapped only input / output
+**	IO mapped input / output
 */
 
 #if defined(NCR_IOMAPPED)
@@ -619,7 +627,7 @@
 **	MEMORY mapped only input / output
 */
 
-#elif defined(NCR_MEMORYMAPPED)
+#else
 
 #define INB(r)             MMIO_INB(r)
 #define INB_OFF(o)         MMIO_INB_OFF(o)
@@ -632,23 +640,6 @@
 #define OUTL(r, val)       MMIO_OUTL(r, val)
 #define OUTL_OFF(o, val)   MMIO_OUTL_OFF(o, val)
 
-/*
-**	IO mapped or MEMORY mapped 
-*/
-
-#else
-
-#define	INB(r)             (np->reg ? MMIO_INB(r) : IOM_INB(r))
-#define	INB_OFF(o)         (np->reg ? MMIO_INB_OFF(o) : IOM_INB_OFF(o))
-#define	INW(r)             (np->reg ? MMIO_INW(r) : IOM_INW(r))
-#define	INL(r)             (np->reg ? MMIO_INL(r) : IOM_INL(r))
-#define	INL_OFF(o)         (np->reg ? MMIO_INL_OFF(o) : IOM_INL_OFF(o))
-
-#define	OUTB(r, val)       (np->reg ? MMIO_OUTB(r, val) : IOM_OUTB(r, val))
-#define	OUTW(r, val)       (np->reg ? MMIO_OUTW(r, val) : IOM_OUTW(r, val))
-#define	OUTL(r, val)       (np->reg ? MMIO_OUTL(r, val) : IOM_OUTL(r, val))
-#define	OUTL_OFF(o, val)   (np->reg ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val))
-
 #endif
 
 /*
@@ -657,6 +648,10 @@
 
 #define OUTONB(r, m)	OUTB(r, INB(r) | (m))
 #define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
 
 /*==========================================================
 **
@@ -700,7 +695,8 @@
 #define	SIR_IGN_RESIDUE		(11)
 #define	SIR_MISSING_SAVE	(12)
 #define	SIR_DATA_IO_IS_OUT	(13)
-#define	SIR_MAX			(13)
+#define	SIR_DATA_IO_IS_IN	(14)
+#define	SIR_MAX			(14)
 
 /*==========================================================
 **
@@ -798,6 +794,10 @@
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+#define UC_DEBUG_ERROR_RECOVERY 17
+#endif
+
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
 
@@ -813,7 +813,6 @@
 	u_long end;
 	u_long select;
 	u_long command;
-	u_long data;
 	u_long status;
 	u_long disconnect;
 	u_long reselect;
@@ -1340,13 +1339,20 @@
 	**-----------------------------------------------
 	*/
 	int    unit;			/* Unit number                       */
-	int    chip;			/* Chip number                       */
+	char   chip_name[8];		/* Chip name                         */
+	char   inst_name[16];		/* Instance name                     */
+	u_int  features;		/* Chip features map		     */
 	struct timer_list timer;	/* Timer link header                 */
 	int	ncr_cache;		/* Cache test variable               */
 	Scsi_Cmnd *waiting_list;	/* Waiting list header for commands  */
 					/* that we can't put into the squeue */
 	u_long	settle_time;		/* Reset in progess		     */
 	u_char	release_stage;		/* Synchronisation stage on release  */
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	u_char	debug_error_recovery;
+	u_char	stalling;
+	u_char	assert_atn;
+#endif
 
 	/*-----------------------------------------------
 	**	Added field to support differences
@@ -1359,9 +1365,6 @@
 	*/
 	u_short	device_id;
 	u_char	revision_id;
-#define ChipDevice	((np)->device_id)
-#define ChipVersion	((np)->revision_id & 0xf0)
-
 	u_char	sv_scntl3;
 	u_char	sv_dmode;
 	u_char	sv_dcntl;
@@ -1370,6 +1373,7 @@
 	u_char	sv_ctest5;
 	u_char	sv_gpcntl;
 	u_char	sv_stest2;
+	u_char	sv_stest4;
 
 	u_char	rv_dmode;
 	u_char	rv_dcntl;
@@ -1377,6 +1381,9 @@
 	u_char	rv_ctest4;
 	u_char	rv_ctest5;
 	u_char	rv_stest2;
+
+	u_char	maxburst;
+	u_char	scsi_mode;
 	u_char	multiplier;
 
 	/*-----------------------------------------------
@@ -1616,8 +1623,8 @@
 	ncrcmd	resel_tmp	[  5];
 	ncrcmd  resel_lun	[ 18];
 	ncrcmd	resel_tag	[ 24];
-	ncrcmd  data_io		[  2];	/* MUST be just before data_in */
-	ncrcmd  data_in		[MAX_SCATTER * 4 + 7];
+	ncrcmd  data_io		[  6];
+	ncrcmd  data_in		[MAX_SCATTER * 4 + 4];
 };
 
 /*
@@ -1642,7 +1649,7 @@
 	ncrcmd	getcc2		[ 14];
 #endif
 	ncrcmd	getcc3		[ 10];
-	ncrcmd  data_out	[MAX_SCATTER * 4 + 7];
+	ncrcmd  data_out	[MAX_SCATTER * 4 + 4];
 	ncrcmd	aborttag	[  4];
 	ncrcmd	abort		[ 22];
 	ncrcmd	snooptest	[  9];
@@ -1664,10 +1671,10 @@
 static	void	ncr_free_ccb	(ncb_p np, ccb_p cp, u_long t, u_long l);
 static	void	ncr_getclock	(ncb_p np, int mult);
 static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
-static	void	ncr_save_bios_setting	(ncb_p np);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_long t,u_long l);
 static	void	ncr_init	(ncb_p np, char * msg, u_long code);
-static	int	ncr_intr	(ncb_p np);
+static	int	ncr_int_sbmc	(ncb_p np);
+static	int	ncr_int_par	(ncb_p np);
 static	void	ncr_int_ma	(ncb_p np);
 static	void	ncr_int_sir	(ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
@@ -1675,7 +1682,7 @@
 static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
 static	void	ncr_opennings	(ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
 #endif
 
@@ -1694,12 +1701,12 @@
 static  void    ncr_wakeup      (ncb_p np, u_long code);
 static	void	ncr_start_reset	(ncb_p np, int settle_delay);
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
 #endif
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id,
-		       u_char revision_id, int chip, u_int base, u_int io_port, 
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, 
+		       ncr_chip *chip, u_int base, u_int io_port, 
 		       int irq, int bus, u_char device_fn);
 
 static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
@@ -1720,24 +1727,13 @@
 **==========================================================
 */
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
 #endif
 
-/*==========================================================
-**
-**
-**      Global static data:	auto configure
-**
-**
-**==========================================================
-*/
-
-static char *ncr_name (ncb_p np)
+static inline char *ncr_name (ncb_p np)
 {
-	static char name[16];
-	sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
-	return (name);
+	return np->inst_name;
 }
 
 
@@ -1783,10 +1779,10 @@
  * Kernel variables referenced in the scripts.
  * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
  */
-static void *script_kvars[] =
+static void *script_kvars[] __initdata =
 	{ (void *)&jiffies };
 
-static	struct script script0 = {
+static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
 	/*
 	**	Claim to be still alive ...
@@ -1881,7 +1877,7 @@
 	**	patch the launch field.
 	**	should look like an idle process.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (skip2),
 	SCR_COPY (8),
@@ -1987,7 +1983,7 @@
 	**	We patch the address part of a
 	**	COPY command with the DSA-register.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (loadpos),
 	/*
@@ -2376,7 +2372,7 @@
 	/*
 	**	and copy back the header to the ccb.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (cleanup0),
 	SCR_COPY (sizeof (struct head)),
@@ -2482,7 +2478,7 @@
 	**
 	**	CAUTION: only little endian architectures supported! XXX
 	*/
-	SCR_COPY (1),
+	SCR_COPY_F (1),
 		NADDR (header.savep),
 		PADDR (disconnect0),
 }/*-------------------------< DISCONNECT0 >--------------*/,{
@@ -2491,7 +2487,7 @@
 	/*
 	**	neither this
 	*/
-	SCR_COPY (1),
+	SCR_COPY_F (1),
 		NADDR (header.goalp),
 		PADDR (disconnect1),
 }/*-------------------------< DISCONNECT1 >--------------*/,{
@@ -2587,7 +2583,7 @@
 	**	This NOP will be patched with LED OFF
 	**	SCR_REG_REG (gpreg, SCR_OR, 0x01)
 	*/
-	SCR_JUMP ^ IFFALSE (0),
+	SCR_NO_OP,
 		0,
 	/*
 	**	make the DSA invalid.
@@ -2609,7 +2605,7 @@
 	**	This NOP will be patched with LED ON
 	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
 	*/
-	SCR_JUMP ^ IFFALSE (0),
+	SCR_NO_OP,
 		0,
 	/*
 	**	... zu nichts zu gebrauchen ?
@@ -2635,7 +2631,7 @@
 	**	This NOP will be patched with LED ON
 	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
 	*/
-	SCR_JUMP ^ IFFALSE (0),
+	SCR_NO_OP,
 		0,
 	/*
 	**	If it's not connected :(
@@ -2758,10 +2754,14 @@
 **	to low-level scsi drivers, we must trust the target 
 **	for actual data direction when we cannot guess it.
 **	The programmed interrupt patches savep, lastp, goalp,
-**	etc.., and restarts the scsi script at data_out.
+**	etc.., and restarts the scsi script at data_out/in.
 */
 	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
 		SIR_DATA_IO_IS_OUT,
+	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		SIR_DATA_IO_IS_IN,
+	SCR_JUMP,
+		PADDR (no_data),
 
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
@@ -2769,15 +2769,7 @@
 **	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**		PADDR (no_data),
-**	SCR_COPY (sizeof (u_long)),
-**		KVAR(SCRIPT_KVAR_JIFFIES),
-**		NADDR (header.stamp.data),
-**	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**		offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTER >=========
 **  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
 **  ||		PADDR (checkatn),
 **  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
@@ -2793,7 +2785,7 @@
 }/*--------------------------------------------------------*/
 };
 
-static	struct scripth scripth0 = {
+static	struct scripth scripth0 __initdata = {
 /*-------------------------< TRYLOOP >---------------------*/{
 /*
 **	Load an entry of the start queue into dsa
@@ -3109,7 +3101,7 @@
 	**	We patch the address part of a COPY command
 	**	with the address of the dsa register ...
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDRH (getcc1),
 	/*
@@ -3247,15 +3239,7 @@
 **	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**		PADDR (no_data),
-**	SCR_COPY (sizeof (u_long)),
-**		KVAR(SCRIPT_KVAR_JIFFIES),
-**		NADDR (header.stamp.data),
-**	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**		offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTER >=========
 **  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
 **  ||		PADDR (dispatch),
 **  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
@@ -3269,7 +3253,7 @@
 **
 **---------------------------------------------------------
 */
-0	/* was (u_long)&ident ? */
+0
 }/*-------------------------< ABORTTAG >-------------------*/,{
 	/*
 	**      Abort a bad reselection.
@@ -3343,7 +3327,9 @@
 **==========================================================
 */
 
+__initfunc(
 void ncr_script_fill (struct script * scr, struct scripth * scrh)
+)
 {
 	int	i;
 	ncrcmd	*p;
@@ -3363,15 +3349,7 @@
 
 	p = scr->data_in;
 
-	*p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
-	*p++ =PADDR (no_data);
-	*p++ =SCR_COPY (sizeof (u_long));
-	*p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-	*p++ =NADDR (header.stamp.data);
-	*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-	*p++ =offsetof (struct dsb, data[ 0]);
-
-	for (i=1; i<MAX_SCATTER; i++) {
+	for (i=0; i<MAX_SCATTER; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
 		*p++ =PADDR (checkatn);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
@@ -3387,15 +3365,7 @@
 
 	p = scrh->data_out;
 
-	*p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
-	*p++ =PADDR (no_data);
-	*p++ =SCR_COPY (sizeof (u_long));
-	*p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-	*p++ =NADDR (header.stamp.data);
-	*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-	*p++ =offsetof (struct dsb, data[ 0]);
-
-	for (i=1; i<MAX_SCATTER; i++) {
+	for (i=0; i<MAX_SCATTER; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
@@ -3419,11 +3389,14 @@
 **==========================================================
 */
 
+__initfunc(
 static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
 	int relocs;
+	int opchanged = 0;
 
 	start = src;
 	end = src + len/4;
@@ -3470,6 +3443,14 @@
 					ncr_name(np), (int) (src-start-1));
 				DELAY (1000000);
 			}
+			/*
+			**	If PREFETCH feature not enabled, remove 
+			**	the NO FLUSH bit if present.
+			*/
+			if ((opcode & SCR_NO_FLUSH) && !(np->features & _F_PFEN)) {
+				dst[-1] = (opcode & ~SCR_NO_FLUSH);
+				++opchanged;
+			}
 			break;
 
 		case 0x0:
@@ -3546,6 +3527,9 @@
 			*dst++ = *src++;
 
 	};
+	if (bootverbose > 1 && opchanged)
+		printf("%s: NO FLUSH bit removed from %d script instructions\n",
+			ncr_name(np), opchanged); 
 }
 
 /*==========================================================
@@ -3595,6 +3579,218 @@
 	if (np) PRINT_LUN(np, cmd->target, cmd->lun);
 }
 
+/*===============================================================
+**
+**	Prepare io register values used by ncr_init() according 
+**	to selected and supported features.
+**
+**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
+**	transfers. 32,64,128 are only supported by 875 and 895 chips.
+**	We use log base 2 (burst length) as internal code, with 
+**	value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ *	Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *	Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ *	Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(ncb_p np, u_char bc)
+{
+	np->rv_ctest4	&= ~0x80;
+	np->rv_dmode	&= ~(0x3 << 6);
+	np->rv_ctest5	&= ~0x4;
+
+	if (!bc) {
+		np->rv_ctest4	|= 0x80;
+	}
+	else {
+		--bc;
+		np->rv_dmode	|= ((bc & 0x3) << 6);
+		np->rv_ctest5	|= (bc & 0x4);
+	}
+}
+
+__initfunc(
+static int ncr_prepare_setting(ncb_p np)
+)
+{
+	u_char	burst_max;
+
+	/*
+	**	Save assumed BIOS setting
+	*/
+
+	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
+	np->sv_dmode	= INB(nc_dmode)  & 0xce;
+	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
+	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
+	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
+	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
+	np->sv_gpcntl	= INB(nc_gpcntl);
+	np->sv_stest2	= INB(nc_stest2) & 0x20;
+	np->sv_stest4	= INB(nc_stest4);
+
+	/*
+	**	Get the frequency of the chip's clock.
+	**	Find the right value for scntl3.
+	*/
+
+	if	(np->features & _F_QUAD)
+		np->multiplier	= 4;
+	else if	(np->features & _F_DBLR)
+		np->multiplier	= 2;
+	else
+		np->multiplier	= 1;
+
+	np->clock_khz	= (np->features & _F_CLK80)? 80000 : 40000;
+	np->clock_khz	*= np->multiplier;
+
+	if (np->clock_khz != 40000)
+		ncr_getclock(np, np->multiplier);
+
+	if	(np->clock_khz <=  25000)	np->rv_scntl3 = 0x01;
+	else if	(np->clock_khz <=  37500)	np->rv_scntl3 = 0x02;
+	else if	(np->clock_khz <=  50000)	np->rv_scntl3 = 0x03;
+	else if	(np->clock_khz <=  75000)	np->rv_scntl3 = 0x04;
+	else if	(np->clock_khz <= 100000)	np->rv_scntl3 = 0x05;
+	else if	(np->clock_khz <= 150000)	np->rv_scntl3 = 0x06;
+	else					np->rv_scntl3 = 0x07;
+
+	/*
+	**	Get on-board RAM bus address when supported
+	*/
+	if (np->features & _F_RAM) {
+		OUTONB(nc_ctest2, 0x8);
+		np->paddr2 = INL(nc_scr0);
+		OUTOFFB(nc_ctest2, 0x8);
+	}
+
+	/*
+	**	Prepare initial value of other IO registers
+	*/
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+	np->rv_dmode	= np->sv_dmode;
+	np->rv_dcntl	= np->sv_dcntl;
+	np->rv_ctest3	= np->sv_ctest3;
+	np->rv_ctest4	= np->sv_ctest4;
+	np->rv_ctest5	= np->sv_ctest5;
+	burst_max	= burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+#else
+	np->rv_dmode	= 0;
+	np->rv_dcntl	= 0;
+	np->rv_ctest3	= 0;
+	np->rv_ctest4	= 0;
+	np->rv_ctest5	= 0;
+	np->rv_stest2	= 0;
+
+	/*
+	**	Select burst length (dwords)
+	*/
+	burst_max	= driver_setup.burst_max;
+	if (burst_max == 255)
+		burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+	if (burst_max > 7)
+		burst_max = 7;
+	if (burst_max > np->maxburst)
+		burst_max = np->maxburst;
+
+	/*
+	**	Select all supported special features
+	*/
+	if (np->features & _F_ERL)
+		np->rv_dmode	|= ERL;		/* Enable Read Line */
+	if (np->features & _F_BOF)
+		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
+	if (np->features & _F_ERMP)
+		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
+	if (np->features & _F_PFEN)
+		np->rv_dcntl	|= PFEN;	/* Prefetch Enable */
+	if (np->features & _F_CLSE)
+		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
+	if (np->features & _F_WRIE)
+		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
+	if (np->features & _F_DFS)
+		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+
+	/*
+	**	Select some other
+	*/
+	if (driver_setup.master_parity)
+		np->rv_ctest4	|= MPEE;	/* Master parity checking */
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+	/*
+	 *	Prepare initial io register bits for burst length
+	 */
+	ncr_init_burst(np, burst_max);
+
+	/*
+	**	Set differential mode.
+	*/
+	switch(driver_setup.diff_support) {
+	case 3:
+		if (INB(nc_gpreg) & 0x08)
+			break;
+	case 2:
+		np->rv_stest2	|= 0x20;
+		break;
+	case 1:
+		np->rv_stest2	|= (np->sv_stest2 & 0x20);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	**	Set irq mode.
+	*/
+	switch(driver_setup.irqm) {
+	case 2:
+		np->rv_dcntl	|= IRQM;
+		break;
+	case 1:
+		np->rv_stest2	|= (np->sv_dcntl & IRQM);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	**	Announce all that stuff to user.
+	*/
+	if (bootverbose > 1) {
+		printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
+			ncr_name(np), np->sv_scntl3, np->rv_scntl3);
+		printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+		printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+		if (np->rv_stest2 & 0x20)
+			printf ("%s: DIFF mode set\n", ncr_name(np));
+	}
+
+	if (bootverbose && np->paddr2)
+		printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
+
+	if (bootverbose && np->ns_sync < 25)
+		printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
+			np->ns_sync < 12 ? "-2": "");
+
+	return 0;
+}
 
 /*
 **	Host attach and initialisations.
@@ -3602,25 +3798,23 @@
 **	Allocate host data and ncb structure.
 **	Request IO region and remap MMIO region.
 **	Do chip initialization.
-**	Try with mmio.
-**	If mmio not possible (misconfigured cache),
-**	retry with io mapped.
 **	If all is OK, install interrupt handling and
 **	start the timer daemon.
 */
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id,
-		       u_char revision_id, int chip, u_int base, u_int io_port, 
+__initfunc(
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, 
+		       ncr_chip *chip, u_int base, u_int io_port, 
 		       int irq, int bus, u_char device_fn)
-
+)
 {
         struct host_data *host_data;
 	ncb_p np;
         struct Scsi_Host *instance = 0;
 	u_long flags = 0;
 
-printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
-	unit, chip, revision_id, base, io_port, irq);
+printf("ncr53c8xx: unit=%d chip=%s rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n",
+	unit, chip->name, chip->revision_id, base, io_port, irq);
 
 	/*
 	**	Allocate host_data structure
@@ -3645,10 +3839,21 @@
 	np->ccb   = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
 	bzero (np->ccb, sizeof (*np->ccb));
 
-	np->unit = unit;
-	np->chip = chip;
-	np->device_id	= device_id;
-	np->revision_id	= revision_id;
+	/*
+	**	Store input informations in the host data structure.
+	*/
+	strncpy(np->chip_name, chip->name, sizeof(np->chip_name) - 1);
+	np->unit	= unit;
+	sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
+	np->device_id	= chip->device_id;
+	np->revision_id	= chip->revision_id;
+	np->features	= chip->features;
+	np->maxwide	= (np->features & _F_WIDE)? 1 : 0;
+	np->ns_sync	= 25;
+	np->clock_khz	= 40000;
+	np->clock_divn	= chip->nr_divisor;
+	np->maxoffs	= chip->offset_max;
+	np->maxburst	= chip->burst_max;
 
 	np->script0  =
 	(struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
@@ -3673,9 +3878,7 @@
 	np->vaddr = remap_pci_mem((u_long) base, (u_long) 128);
 	if (!np->vaddr) {
 		printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
 		goto attach_error;
-#endif
 	}
 	else
 		if (bootverbose > 1)
@@ -3699,97 +3902,16 @@
 	np->port = io_port;
 
 	/*
-	**	Save initial value of some io registers.
-	*/
-
-	ncr_save_bios_setting(np);
-
-	/*
 	**	Do chip dependent initialization.
 	*/
-
-	np->maxwide = 0;
-	np->rv_scntl3 = 0x13;	/* default: 40MHz clock */
-	np->ns_sync   = 25;
-	np->clock_khz	= 40000;
-	np->clock_divn	= 4;
-	np->maxoffs   = 8;
-	np->multiplier = 1;
-
-	/*
-	**	Get the frequency of the chip's clock.
-	**	Find the right value for scntl3.
-	*/
-
-	switch (device_id) {
-	case PCI_DEVICE_ID_NCR_53C825:
-		np->maxwide = 1;
-		break;
-	case PCI_DEVICE_ID_NCR_53C860:
-		if (driver_setup.ultra_scsi) {
-			np->rv_scntl3 = 0x15;
-			np->clock_khz = 80000;
-			np->ns_sync   = 12;
-		}
-		else
-			np->rv_scntl3 = 0x35;	/* always assume 80MHz clock for 860 */
-		np->clock_divn	= 5;
-		break;
-	case PCI_DEVICE_ID_NCR_53C875:
-	case PCI_DEVICE_ID_NCR_53C885:
-		np->maxwide = 1;
-		if (driver_setup.special_features)
-			np->maxoffs = 16;
-		np->clock_divn	= 5;
-		if (device_id == PCI_DEVICE_ID_NCR_53C875)
-			ncr_getclock(np, revision_id >= 2 ? 2 : 1);
-		else
-			ncr_getclock(np, 2);
-		break;
-	case PCI_DEVICE_ID_NCR_53C895:
-	case PCI_DEVICE_ID_NCR_53C896:
-		np->maxwide = 1;
-		if (driver_setup.special_features)
-			np->maxoffs = 31;
-		np->clock_divn	= 7;
-		ncr_getclock(np, 4);
-		break;
-	}
-
-	/*
-	**	Get on-board RAM bus address when supported
-	*/
-	switch (device_id) {
-	case PCI_DEVICE_ID_NCR_53C825:
-		if (revision_id < 0x10)
-			break;
-	case PCI_DEVICE_ID_NCR_53C875:
-	case PCI_DEVICE_ID_NCR_53C885:
-	case PCI_DEVICE_ID_NCR_53C895:
-	case PCI_DEVICE_ID_NCR_53C896:
-		if (driver_setup.special_features) {
-			OUTONB(nc_ctest2, 0x8);
-			np->paddr2 = INL(nc_scr0);
-			OUTOFFB(nc_ctest2, 0x8);
-		}
-		break;
-	}
-
-	if (bootverbose && np->paddr2)
-		printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
-
-	if (bootverbose && np->ns_sync < 25)
-		printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
-			np->ns_sync < 12 ? "-2": "");
+	(void)ncr_prepare_setting(np);
 
 #ifndef NCR_IOMAPPED
 	if (np->paddr2 && sizeof(struct script) <= 4096) {
 		np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
 		if (!np->vaddr2) {
 			printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-#ifdef NCR_MEMORYMAPPED
 			goto attach_error;
-#endif
 		}
 		else
 			if (bootverbose > 1)
@@ -3831,16 +3953,23 @@
 	np->ccb->p_ccb		= vtophys (np->ccb);
 
 	/*
-	**	init data structure
+	**    Patch the script for LED support.
+	*/
+
+	if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+		np->features |= _F_LED0;
+		np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
+		np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+		np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+	}
+
+	/*
+	**	init data structure
 	*/
 
 	np->jump_tcb.l_cmd	= SCR_JUMP;
 	np->jump_tcb.l_paddr	= NCB_SCRIPTH_PHYS (np, abort);
 
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-retry_chip_init:
-#endif
-
 	/*
 	**  Get SCSI addr of host adapter (set by bios?).
 	*/
@@ -3864,14 +3993,6 @@
 	*/
 
 	if (ncr_snooptest (np)) {
-#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
-		if (np->reg) {
-printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
-	ncr_name(np), (u_long) np->port);
-			np->reg = 0;
-			goto retry_chip_init;
-		}
-#endif
 		printf ("CACHE INCORRECTLY CONFIGURED.\n");
 		goto attach_error;
 	};
@@ -3962,18 +4083,25 @@
 
 attach_error:
 	if (!instance) return -1;
+	printf("%s: detaching...\n", ncr_name(np));
 #ifndef NCR_IOMAPPED
 	if (np->vaddr) {
+#ifdef DEBUG_NCR53C8XX
 		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
 		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
 	}
 	if (np->vaddr2) {
+#ifdef DEBUG_NCR53C8XX
 		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
 		unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
 	}
 #endif
 	if (np->port) {
+#ifdef DEBUG_NCR53C8XX
 		printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
 		release_region(np->port, 128);
 	}
 	scsi_unregister(instance);
@@ -3984,47 +4112,6 @@
 /*==========================================================
 **
 **
-**	Process pending device interrupts.
-**
-**
-**==========================================================
-*/
-int ncr_intr(np)
-	ncb_p np;
-{
-	int n = 0;
-	u_long flags;
-
-	save_flags(flags); cli();
-
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-
-#ifdef SCSI_NCR_PARANOIA
-	if (INB(nc_istat) & (INTF|SIP|DIP)) {
-		/*
-		**	Repeat until no outstanding ints
-		*/
-		do {
-#endif
-			ncr_exception (np);
-#ifdef SCSI_NCR_PARANOIA
-		} while (INB(nc_istat) & (INTF|SIP|DIP));
-
-		n=1;
-		np->ticks = 5 * HZ;
-	};
-#endif
-
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-
-	restore_flags(flags);
-
-	return (n);
-}
-
-/*==========================================================
-**
-**
 **	Start execution of a SCSI command.
 **	This is called from the generic SCSI driver.
 **
@@ -4107,7 +4194,7 @@
 	**
 	**----------------------------------------------------
 	*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
 	cp->phys.header.stamp.start = jiffies;
 #endif
@@ -4337,25 +4424,30 @@
 	*/
 
 	cp->segments = segments;
+	if (!cp->data_len)
+		xfer_direction = XferNone;
 
 	switch (xfer_direction) {
+		u_long endp;
 	default:
 	case XferBoth:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
-	     cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16;
-	     break;
+		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+		cp->phys.header.goalp = cp->phys.header.savep;
+		break;
 	case XferIn:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
-	     cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-	     break;
+		endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+		cp->phys.header.goalp = endp + 8;
+		cp->phys.header.savep = endp - segments*16;
+		break;
 	case XferOut:
-	     cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
-	     cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-	     break;
+		endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+		cp->phys.header.goalp = endp + 8;
+		cp->phys.header.savep = endp - segments*16;
+		break;
 	case XferNone:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
-	     cp->phys.header.goalp = cp->phys.header.savep;
-	     break;
+		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+		cp->phys.header.goalp = cp->phys.header.savep;
+		break;
 	}
 
 	cp->phys.header.lastp = cp->phys.header.savep;
@@ -4463,6 +4555,9 @@
 	**	Script processor may be waiting for reselect.
 	**	Wake it up.
 	*/
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (!np->stalling)
+#endif
 	OUTB (nc_istat, SIGP);
 
 	/*
@@ -4530,6 +4625,11 @@
 	u_long flags;
 	int found;
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling)
+		np->stalling = 0;
+#endif
+
 	save_flags(flags); cli();
 /*
  * Return immediately if reset is in progress.
@@ -4607,6 +4707,11 @@
 	int found;
 	int retv;
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling == 2)
+		np->stalling = 0;
+#endif
+
 	save_flags(flags); cli();
 /*
  * First, look for the scsi command in the waiting list
@@ -4663,6 +4768,9 @@
 	**      processor will sleep on SEL_WAIT_RESEL.
 	**      Let's wake it up, since it may have to work.
 	*/
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (!np->stalling)
+#endif
 	OUTB (nc_istat, SIGP);
 
 	restore_flags(flags);
@@ -4697,7 +4805,7 @@
 **	Set release_stage to 1 and wait that ncr_timeout() set it to 2.
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: stopping the timer\n", ncr_name(np));
 #endif
 	np->release_stage = 1;
@@ -4710,7 +4818,7 @@
 **	Disable chip interrupts
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: disabling chip interrupts\n", ncr_name(np));
 #endif
 	OUTW (nc_sien , 0);
@@ -4720,7 +4828,7 @@
 **	Free irq
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing irq %d\n", ncr_name(np), irq);
 #endif
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
@@ -4758,17 +4866,17 @@
 	*/
 
 #ifndef NCR_IOMAPPED
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 	unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
 #endif
 	unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
 #endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
 #endif
 	release_region(np->port, 128);
@@ -4783,7 +4891,7 @@
 		printf("%s: shall free an active ccb (host_status=%d)\n",
 			ncr_name(np), cp->host_status);
 		}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
 #endif
 		m_free(cp, sizeof(*cp));
@@ -4798,7 +4906,7 @@
 		for (lun = 0 ; lun < MAX_LUN ; lun++) {
 			lp = tp->lp[lun];
 			if (lp) {
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
 				m_free(lp, sizeof(*lp));
@@ -4851,7 +4959,7 @@
 	**	timestamp
 	**	Optional, spare some CPU time
 	*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	ncb_profile (np, cp);
 #endif
 
@@ -5158,46 +5266,6 @@
 	};
 }
 
-/*===============================================================
-**
-**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
-**	transfers. 32,64,128 are only supported by 875 and 895 chips.
-**	We use log base 2 (burst length) as internal code, with 
-**	value 0 meaning "burst disabled".
-**
-**===============================================================
-*/
-
-/*
- *	Burst length from burst code.
- */
-#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
-
-/*
- *	Burst code from io register bits.
- */
-#define burst_code(dmode, ctest4, ctest5) \
-	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
-
-/*
- *	Set initial io register bits from burst code.
- */
-static void ncr_init_burst(ncb_p np, u_char bc)
-{
-	np->rv_ctest4	&= ~0x80;
-	np->rv_dmode	&= ~(0x3 << 6);
-	np->rv_ctest5	&= ~0x4;
-
-	if (!bc) {
-		np->rv_ctest4	|= 0x80;
-	}
-	else {
-		--bc;
-		np->rv_dmode	|= ((bc & 0x3) << 6);
-		np->rv_ctest5	|= (bc & 0x4);
-	}
-}
-
 /*==========================================================
 **
 **
@@ -5212,7 +5280,6 @@
 	int	i;
 	u_long	usrsync;
 	u_char	usrwide;
-	u_char	burst_max;
 
 	/*
 	**	Reset chip.
@@ -5236,7 +5303,6 @@
 	/*
 	**	Start at first entry.
 	*/
-
 	np->squeueput = 0;
 	np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
 	np->script0->start0  [0] = SCR_INT ^ IFFALSE (0);
@@ -5249,161 +5315,30 @@
 	/*
 	**	Init chip.
 	*/
-#if defined SCSI_NCR_TRUST_BIOS_SETTING
-	np->rv_dmode	= np->sv_dmode;
-	np->rv_dcntl	= np->sv_dcntl;
-	np->rv_ctest3	= np->sv_ctest3;
-	np->rv_ctest4	= np->sv_ctest4;
-	np->rv_ctest5	= np->sv_ctest5;
-	burst_max	= burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-#else
-	np->rv_dmode	= 0;
-	np->rv_dcntl	= 0;
-	np->rv_ctest3	= 0;
-	np->rv_ctest4	= 0;
-	burst_max	= driver_setup.burst_max;
-	if (burst_max == 255)
-		burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
-	if (burst_max > 7)
-		burst_max = 7;
-
-/**	NCR53C810			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
-		burst_max	= burst_max < 4 ? burst_max : 4;
-		if (driver_setup.special_features)
-			np->rv_dmode	=  ERL;		/* read line */
-	}
-	else
-/**	NCR53C815			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
-		burst_max	= burst_max < 4 ? burst_max : 4;
-		if (driver_setup.special_features)
-			np->rv_dmode	= BOF | ERL;	/* burst opcode fetch, read line */
-	}
-	else
-/**	NCR53C825			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
-		burst_max	= burst_max < 4 ? burst_max : 4;
-		if (driver_setup.special_features)
-			np->rv_dmode	= BOF | ERL;	/* burst opcode fetch, read line */
-	}
-	else
-/**	NCR53C810A or NCR53C860		**/
-	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
-		burst_max	= burst_max < 4 ? burst_max : 4;
-		if (driver_setup.special_features) {
-			np->rv_dmode	= BOF | ERMP | ERL;
-						/* burst op-code fetch, read multiple */
-						/* read line */
-			np->rv_dcntl	= PFEN | CLSE;
-						/* prefetch, cache line size */
-			np->rv_ctest3	= WRIE;	/* write and invalidate */
-		}
-	}
-	else
-/**	NCR53C825A or NCR53C875 or NCR53C885 or NCR53C895 or NCR53C896	**/
-	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C875 ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C885 ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C895 ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C896) {
-		if (!driver_setup.special_features)
-			burst_max	= burst_max < 4 ? burst_max : 4;
-		else {
-			burst_max	= burst_max < 7 ? burst_max : 7;
-			np->rv_dmode	= BOF | ERMP | ERL;
-						/* burst op-code fetch, read multiple */
-						/* read line, burst 128 (ctest5&4) */
-			np->rv_dcntl	= PFEN | CLSE;
-						/* prefetch, cache line size */
-			np->rv_ctest3	= WRIE;	/* write and invalidate */
-			np->rv_ctest5	= DFS;	/* large dma fifo (0x20) */
-		}
-	}
-/**	OTHERS				**/
-	else {
-		burst_max	= burst_max < 4 ? burst_max : 4;
-	}
-#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
-
-	/*
-	 *	Prepare initial io register bits for burst length
-	 */
-	ncr_init_burst(np, burst_max);
-
-	/*
-	**	Set differential mode.
-	*/
-	switch(driver_setup.diff_support) {
-	case 3:
-		if (INB(nc_gpreg) & 0x08)
-			break;
-	case 2:
-		np->rv_stest2	|= 0x20;
-		break;
-	case 1:
-		np->rv_stest2	|= (np->sv_stest2 & 0x20);
-		break;
-	default:
-		break;
-	}
 
-	/*
-	**	Set irq mode.
-	*/
-	switch(driver_setup.irqm) {
-	case 2:
-		np->rv_dcntl	|= IRQM;
-		break;
-	case 1:
-		np->rv_stest2	|= (np->sv_dcntl & IRQM);
-		break;
-	default:
-		break;
-	}
-
-	if (bootverbose > 1) {
-		printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
-			ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
-	}
-	if (bootverbose > 1) {
-		printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
-			ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
-		if (np->rv_stest2 & 0x20)
-			printf ("%s: setting up differential mode\n", ncr_name(np));
-	}
-
-	OUTB (nc_istat,  0x00   );      /*  Remove Reset, abort ...	     */
+	OUTB (nc_istat,  0x00   );	/*  Remove Reset, abort */
 	if (driver_setup.scsi_parity)
-		OUTB (nc_scntl0, 0xca   );      /*  full arb., ena parity, par->ATN  */
+		OUTB (nc_scntl0, 0xca);	/*  full arb., ena parity, par->ATN  */
 	else
-		OUTB (nc_scntl0, 0xc0   );      /*  full arb., (no parity)           */
-
-	OUTB (nc_scntl1, 0x00	);	/*  odd parity, and remove CRST!!    */
+		OUTB (nc_scntl0, 0xc0);	/*  full arb., (no parity) */
 
-	ncr_selectclock(np, np->rv_scntl3);
+	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
 
-	OUTB (nc_scid  , RRE|np->myaddr);/*  host adapter SCSI address       */
-	OUTW (nc_respid, 1ul<<np->myaddr);/*  id to respond to		     */
-	OUTB (nc_istat , SIGP	);	/*  Signal Process		     */
-	OUTB (nc_dmode , np->rv_dmode);	/*  Burst length = 2 .. 16 transfers */
+	ncr_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
 
-	if (driver_setup.special_features && np->rv_ctest5)
-		OUTB (nc_ctest5, np->rv_ctest5);     /*  large fifo + large burst */
+	OUTB (nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
+	OUTW (nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
+	OUTB (nc_istat , SIGP	);		/*  Signal Process */
+	OUTB (nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
+	OUTB (nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
 
-	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);/* no single step mode, protect SFBR*/
-	OUTB (nc_ctest3, np->rv_ctest3);     /* write and invalidate       */
-
-	if (driver_setup.master_parity)
-		OUTB (nc_ctest4, MPEE|np->rv_ctest4);	/*  enable master parity checking    */
-	else
-		OUTB (nc_ctest4, 0x00|np->rv_ctest4);	/*  disable master parity checking   */
+	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
+	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
+	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
 
-	OUTB (nc_stest2, EXT|np->rv_stest2);	/*  Extended Sreq/Sack filtering     */
-	OUTB (nc_stest3, TE     );	/*  TolerANT enable		     */
-	OUTB (nc_stime0, 0x0d	);	/*  HTH = disable  STO = 0.4 sec.    */
-					/*  0.25 sec recommended for scsi 1  */
+	OUTB (nc_stest2, EXT|np->rv_stest2);	/* Extended Sreq/Sack filtering */
+	OUTB (nc_stest3, TE);			/* TolerANT enable */
+	OUTB (nc_stime0, 0x0d	);		/* HTH disabled  STO 0.4 sec. */
 
 	/*
 	**	Reinitialize usrsync.
@@ -5436,31 +5371,11 @@
 	np->disc = 0;
 
 	/*
-	**	Fill in target structure.
+	**    Enable GPIO0 pin for writing if LED support.
 	*/
 
-	for (i=0;i<MAX_TARGET;i++) {
-		tcb_p tp = &np->target[i];
-
-		tp->sval    = 0;
-		tp->wval    = np->rv_scntl3;
-
-		tp->usrsync = usrsync;
-		tp->usrwide = usrwide;
-
-		ncr_negotiate (np, tp);
-	}
-
-	/*
-	**    Enable GPIO0 pin for writing.
-	**    Patch the script for LED support.
-	*/
-
-	if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+	if (np->features & _F_LED0) {
 		OUTOFFB (nc_gpcntl, 0x01);
-		np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
-		np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
-		np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
 	}
 
 	/*
@@ -5480,6 +5395,31 @@
 	OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
 
 	/*
+	**	For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+	*/
+	if (np->features & _F_ULTRA2) {
+		OUTONW (nc_sien, SBMC);
+		np->scsi_mode = INB (nc_stest4) & SMODE;
+	}
+
+	/*
+	**	Fill in target structure.
+	**	Prepare sync negotiation according to actual SCSI bus mode.
+	*/
+
+	for (i=0;i<MAX_TARGET;i++) {
+		tcb_p tp = &np->target[i];
+
+		tp->sval    = 0;
+		tp->wval    = np->rv_scntl3;
+
+		tp->usrsync = usrsync;
+		tp->usrwide = usrwide;
+
+		ncr_negotiate (np, tp);
+	}
+
+	/*
 	**    Start script processor.
 	*/
 
@@ -5502,14 +5442,12 @@
 
 	u_long minsync = tp->usrsync;
 
-	if	(driver_setup.ultra_scsi >= 2) {
-		if (minsync < 10) minsync=10;
-	}
-	else if	(driver_setup.ultra_scsi == 1) {
-		if (minsync < 12) minsync=12;
-	}
-	else {
-		if (minsync < 25) minsync=25;
+	/*
+	**	SCSI bus mode limit
+	*/
+
+	if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+		if (minsync < 12) minsync = 12;
 	}
 
 	/*
@@ -5628,7 +5566,7 @@
 	*fakp		= fak - 4;
 	*scntl3p	= ((idiv+1) << 4) + (fac < 25 ? ULTRA : 0);
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp);
 #endif
 
@@ -5867,7 +5805,7 @@
 **----------------------------------------------------
 */
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 
 static void ncr_usercmd (ncb_p np)
 {
@@ -5897,7 +5835,7 @@
 		break;
 
 	case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 		ncr_debug = np->user.data;
 #endif
 		break;
@@ -5929,12 +5867,106 @@
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	case UC_DEBUG_ERROR_RECOVERY:
+		np->debug_error_recovery = np->user.data;
+		break;
+#endif
 	}
 	np->user.cmd=0;
 }
 #endif
 
 
+/*=====================================================================
+**
+**    Embedded error recovery debugging code.
+**
+**=====================================================================
+**
+**    This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
+**    It only can be enabled after boot-up with a control command.
+**
+**    Every 30 seconds the timer handler of the driver decides to 
+**    change the behaviour of the driver in order to trigger errors.
+**
+**    If last command was "debug_error_recovery sge", the driver 
+**    sets sync offset of all targets that use sync transfers to 2, 
+**    and so hopes a SCSI gross error at the next read operation.
+**
+**    If last command was "debug_error_recovery abort", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to abort or reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery reset", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery parity", the driver 
+**    will assert ATN on the next DATA IN phase mismatch, and so will 
+**    behave as if a parity error had been detected.
+**
+**    The command "debug_error_recovery none" makes the driver behave 
+**    normaly.
+**
+**=====================================================================
+*/
+
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+static void ncr_trigger_errors (ncb_p np)
+{
+	/*
+	** 	If np->debug_error_recovery is not zero, we want to 
+	**	simulate common errors in order to test error recovery.
+	*/
+	do {
+		static u_long last = 0l;
+
+		if (!np->debug_error_recovery)
+			break;
+		if (!last)
+			last = jiffies;
+		else if (jiffies < last + 30*HZ)
+			break;
+		last = jiffies;
+		/*
+		 * This one triggers SCSI gross errors.
+		 */
+		if (np->debug_error_recovery == 1) {
+			int i;
+			printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
+			for (i = 0 ; i < MAX_TARGET ; i++) {
+				if (np->target[i].sval & 0x1f) {
+					np->target[i].sval &= ~0x1f;
+					np->target[i].sval += 2;
+				}
+			}
+		}
+		/*
+		 * This one triggers abort from the mid-level driver.
+		 */
+		else if (np->debug_error_recovery == 2) {
+			printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
+			np->stalling = 2;
+		}
+		/*
+		 * This one triggers reset from the mid-level driver.
+		 */
+		else if (np->debug_error_recovery == 3) {
+			printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
+			np->stalling = 3;
+		}
+		/*
+		 * This one set ATN on phase mismatch in DATA IN phase and so 
+		 * will behave as on scsi parity error detected.
+		 */
+		else if (np->debug_error_recovery == 4) {
+			printf("%s: testing data in parity error...\n", ncr_name(np));
+			np->assert_atn = 1;
+		}
+	} while (0);
+}
+#endif
 
 /*==========================================================
 **
@@ -5977,6 +6009,10 @@
 
 	add_timer(&np->timer);
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	ncr_trigger_errors (np);
+#endif
+
 	/*
 	**	If we are resetting the ncr, wait for settle_time before 
 	**	clearing it. Then command processing will be resumed.
@@ -6084,6 +6120,9 @@
 			*/
 			ncr_complete (np, cp);
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+			if (!np->stalling)
+#endif
 			OUTB (nc_istat, SIGP);
 		}
 		restore_flags(flags);
@@ -6138,6 +6177,7 @@
 {
 	u_int32	dsp;
 	int	script_ofs;
+	int	script_size;
 	char	*script_name;
 	u_char	*script_base;
 	int	i;
@@ -6146,11 +6186,13 @@
 
 	if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
 		script_ofs	= dsp - np->p_script;
+		script_size	= sizeof(struct script);
 		script_base	= (u_char *) np->script;
 		script_name	= "script";
 	}
 	else {
 		script_ofs	= dsp - np->p_scripth;
+		script_size	= sizeof(struct scripth);
 		script_base	= (u_char *) np->scripth;
 		script_name	= "scripth";
 	}
@@ -6162,7 +6204,7 @@
 		(unsigned)INL (nc_dbc));
 
 	if (((script_ofs & 3) == 0) &&
-	    (unsigned)script_ofs < sizeof(struct script)) {
+	    (unsigned)script_ofs < script_size) {
 		printf ("%s: script cmd = %08x\n", ncr_name(np),
 			(int) *(ncrcmd *)(script_base + script_ofs));
 	}
@@ -6173,13 +6215,36 @@
         printf (".\n");
 }
 
-/*==========================================================
-**
+/*============================================================
 **
 **	ncr chip exception handler.
 **
+**============================================================
 **
-**==========================================================
+**	In normal cases, interrupt conditions occur one at a 
+**	time. The ncr is able to stack in some extra registers 
+**	other interrupts that will occurs after the first one.
+**	But severall interrupts may occur at the same time.
+**
+**	We probably should only try to deal with the normal 
+**	case, but it seems that multiple interrupts occur in 
+**	some cases that are not abnormal at all.
+**
+**	The most frequent interrupt condition is Phase Mismatch.
+**	We should want to service this interrupt quickly.
+**	A SCSI parity error may be delivered at the same time.
+**	The SIR interrupt is not very frequent in this driver, 
+**	since the INTFLY is likely used for command completion 
+**	signaling.
+**	The Selection Timeout interrupt may be triggered with 
+**	IID and/or UDC.
+**	The SBMC interrupt (SCSI Bus Mode Change) may probably 
+**	occur at any time.
+**
+**	This handler try to deal as cleverly as possible with all
+**	the above.
+**
+**============================================================
 */
 
 void ncr_exception (ncb_p np)
@@ -6193,14 +6258,23 @@
 	*/
 	while ((istat = INB (nc_istat)) & INTF) {
 		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling)
+		OUTB (nc_istat, INTF);
+	else
+#endif
 		OUTB (nc_istat, (istat & SIGP) | INTF);
 		np->profile.num_fly++;
 		ncr_wakeup (np, 0);
 	};
 
-	if (!(istat & (SIP|DIP))) {
+	if (!(istat & (SIP|DIP)))
 		return;
-	}
+
+	np->profile.num_int++;
+
+	if (istat & CABRT)
+		OUTB (nc_istat, CABRT);
 
 	/*
 	**	Steinbach's Guideline for Systems Programming:
@@ -6209,7 +6283,6 @@
 
 	sist  = (istat & SIP) ? INW (nc_sist)  : 0;
 	dstat = (istat & DIP) ? INB (nc_dstat) : 0;
-	np->profile.num_int++;
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printf ("<%d|%x:%x|%x:%x>",
@@ -6217,234 +6290,121 @@
 			dstat,sist,
 			(unsigned)INL(nc_dsp),
 			(unsigned)INL(nc_dbc));
-	if ((dstat==DFE) && (sist==PAR)) return;
 
-/*==========================================================
-**
-**	First the normal cases.
-**
-**==========================================================
-*/
-	/*-------------------------------------------
-	**	SCSI reset
-	**-------------------------------------------
-	*/
-
-	if (sist & RST) {
-		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
-		return;
-	};
-
-	/*-------------------------------------------
-	**	selection timeout
+	/*========================================================
+	**	First, interrupts we want to service cleanly.
 	**
-	**	IID excluded from dstat mask!
-	**	(chip bug)
-	**-------------------------------------------
-	*/
-
-	if ((sist  & STO) &&
-		!(sist  & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR))) {
-		ncr_int_sto (np);
-		return;
-	};
-
-	/*-------------------------------------------
-	**      Phase mismatch.
-	**-------------------------------------------
-	*/
-
-	if ((sist  & MA) &&
-		!(sist  & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		ncr_int_ma (np);
+	**	Phase mismatch is the most frequent interrupt, and 
+	**	so we have to service it as quickly and as cleanly 
+	**	as possible.
+	**	Programmed interrupts are rarely used in this driver,
+	**	but we must handle them cleanly anyway.
+	**	We try to deal with PAR and SBMC combined with 
+	**	some other interrupt(s).
+	**=========================================================
+	*/
+
+	if (!(sist  & (STO|GEN|HTH|SGE|UDC|RST)) &&
+	    !(dstat & (MDPE|BF|ABRT|IID))) {
+		if ((sist & SBMC) && ncr_int_sbmc (np))
+			return;
+		if ((sist & PAR)  && ncr_int_par  (np))
+			return;
+		if (sist & MA) {
+			ncr_int_ma (np);
+			return;
+		}
+		if (dstat & SIR) {
+			ncr_int_sir (np);
+			return;
+		}
+		if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
+			printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
+				ncr_name(np), sist, dstat);
+		OUTONB (nc_dcntl, (STD|NOCOM));
 		return;
 	};
 
-	/*----------------------------------------
-	**	move command with length 0
-	**----------------------------------------
+	/*========================================================
+	**	Now, interrupts that need some fixing up.
+	**	Order and multiple interrupts is so less important.
+	**
+	**	If SRST has been asserted, we just reset the chip.
+	**
+	**	Selection is intirely handled by the chip. If the 
+	**	chip says STO, we trust it. Seems some other 
+	**	interrupts may occur at the same time (UDC, IID), so 
+	**	we ignore them. In any case we do enough fix-up 
+	**	in the service routine.
+	**	We just exclude some fatal dma errors.
+	**=========================================================
 	*/
 
-	if ((dstat & IID) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR)) &&
-		((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
-		/*
-		**      Target wants more data than available.
-		**	The "no_data" script will do it.
-		*/
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+	if (sist & RST) {
+		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
 		return;
 	};
 
-	/*-------------------------------------------
-	**	Programmed interrupt
-	**-------------------------------------------
-	*/
-
-	if ((dstat & SIR) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|IID)) &&
-		(INB(nc_dsps) <= SIR_MAX)) {
-		ncr_int_sir (np);
+	if ((sist & STO) &&
+		!(dstat & (MDPE|BF|ABRT))) {
+		ncr_int_sto (np);
 		return;
 	};
 
-	/*========================================
-	**	do the register dump
-	**========================================
+	/*=========================================================
+	**	Now, interrupts we are not able to recover cleanly.
+	**	(At least for the moment).
+	**
+	**	Do the register dump.
+	**	Log message for real hard errors.
+	**	Clear all fifos.
+	**	For MDPE, BF, ABORT, IID, SGE and HTH we reset the 
+	**	BUS and the chip.
+	**	We are more soft for UDC.
+	**=========================================================
 	*/
 	if (jiffies - np->regtime > 10*HZ) {
-		int i;
 		np->regtime = jiffies;
-		for (i=0; i<sizeof(np->regdump); i++)
+		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
 		np->regdump.nc_sist  = sist;
 	};
 
-	/*=========================================
-	**	log message for real hard errors
-	**=========================================
-	*/
-	ncr_log_hard_error(np, sist, dstat);
-
-	/*----------------------------------------
-	**	clean up the dma fifo
-	**----------------------------------------
-	*/
-
-	if ( (INB(nc_sstat0) & (ILF|ORF|OLF)   ) ||
-	     (INB(nc_sstat1) & (FF3210)	) ||
-	     (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) ||	/* wide .. */
-	     !(dstat & DFE)) {
-		printf ("%s: have to clear fifos.\n", ncr_name (np));
-		OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
-		OUTONB (nc_ctest3, CLF);		/* clear dma fifo  */
-	}
-
-	/*----------------------------------------
-	**	handshake timeout
-	**----------------------------------------
-	*/
-
-	if (sist & HTH) {
-		printf ("%s: handshake timeout\n", ncr_name(np));
-		OUTB (nc_scntl1, CRST);
-		DELAY (1000);
-		OUTB (nc_scntl1, 0x00);
-		OUTB (nc_scr0, HS_FAIL);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-		return;
-	}
-
-	/*----------------------------------------
-	**	unexpected disconnect
-	**----------------------------------------
-	*/
-
-	if ((sist  & UDC) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		OUTB (nc_scr0, HS_UNEXPECTED);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-		return;
-	};
-
-	/*----------------------------------------
-	**	cannot disconnect
-	**----------------------------------------
-	*/
-
-	if ((dstat & IID) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR)) &&
-		((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
-		/*
-		**      Unexpected data cycle while waiting for disconnect.
-		**	LDSC and CON bits may help in order to understand 
-		**	what really happened. Print some info message and let 
-		**	the reset function reset the BUS and the NCR.
-		*/
-		printf("%s:%d: data cycle while waiting for disconnect, LDSC=%d CON=%d\n",
-			ncr_name (np), (int)(INB(nc_ctest0)&0x0f),
-			(0!=(INB(nc_sstat2)&LDSC)), (0!=(INB(nc_scntl1)&ISCON)));
-	};
-
-	/*----------------------------------------
-	**	single step
-	**----------------------------------------
-	*/
-
-	if ((dstat & SSI) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		OUTONB (nc_dcntl, (STD|NOCOM));
-		return;
-	};
-
-/*
-**	@RECOVER@ HTH, SGE, ABRT.
-**
-**	We should try to recover from these interrupts.
-**	They may occur if there are problems with synch transfers, or 
-**	if targets are switched on or off while the driver is running.
-*/
-
-	if (sist & SGE) {
-		OUTONB (nc_ctest3, CLF);	/* clear scsi offsets */
-	}
-
-	/*
-	**	Freeze controller to be able to read the messages.
-	*/
-
-	if (DEBUG_FLAGS & DEBUG_FREEZE) {
-		unsigned char val;
-		for (i=0; i<0x60; i++) {
-			switch (i%16) {
-
-			case 0:
-				printf ("%s: reg[%d0]: ",
-					ncr_name(np),i/16);
-				break;
-			case 4:
-			case 8:
-			case 12:
-				printf (" ");
-				break;
-			};
-			val = INB_OFF(i);
-			printf (" %x%x", val/16, val%16);
-			if (i%16==15) printf (".\n");
-		}
-
-		del_timer(&np->timer);
+	ncr_log_hard_error(np, sist, dstat);
 
-		printf ("%s: halted!\n", ncr_name(np));
-		/*
-		**	don't restart controller ...
-		*/
-		OUTB (nc_istat,  SRST);
+	printf ("%s: have to clear fifos.\n", ncr_name (np));
+	OUTB (nc_stest3, TE|CSF);
+	OUTONB (nc_ctest3, CLF);
+
+	if ((sist & (SGE)) ||
+		(dstat & (MDPE|BF|ABORT|IID))) {
+		ncr_start_reset(np, 2);
 		return;
 	};
 
-#ifdef NCR_FREEZE
-	/*
-	**	Freeze system to be able to read the messages.
-	*/
-	printf ("ncr: fatal error: system halted - press reset to reboot ...");
-	cli();
-	for (;;);
-#endif
+	if (sist & HTH) {
+		printf ("%s: handshake timeout\n", ncr_name(np));
+		ncr_start_reset(np, 2);
+		return;
+	};
 
-	/*
-	**	sorry, have to kill ALL jobs ...
-	*/
+	if (sist & UDC) {
+		printf ("%s: unexpected disconnect\n", ncr_name(np));
+		if (INB (nc_scr1) != 0xff) {
+			OUTB (nc_scr1, HS_UNEXPECTED);
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+		};
+		ncr_start_reset(np, 2);
+		return;
+	};
 
-	ncr_start_reset(np, 2);
+	/*=========================================================
+	**	We just miss the cause of the interrupt. :(
+	**	Print a message. The timeout will do the real work.
+	**=========================================================
+	*/
+	printf ("%s: unknown interrupt\n", ncr_name(np));
 }
 
 /*==========================================================
@@ -6503,6 +6463,70 @@
 
 /*==========================================================
 **
+**	ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+**	I'm not quite sure of what is to be done in such a
+**	situation.
+**	For now,
+**	Reset the bus if some devices use too fast sync transfers.
+**	Otherwise, just try to renegotiate sync with targets. 
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (ncb_p np)
+{
+	u_char scsi_mode = INB (nc_stest4) & SMODE;
+	int i;
+	int oversync;
+
+	printf("%s: SCSI bus mode change from %x to %x\n", ncr_name(np),
+		np->scsi_mode, scsi_mode);
+
+	if (scsi_mode == np->scsi_mode)
+		return 0;
+
+	np->scsi_mode = scsi_mode;
+	oversync = 0;
+	for (i = 0; i < MAX_TARGET; i++) {
+		tcb_p tp = &np->target[i];
+
+		if (np->ns_sync < 12 && tp->maxoffs && tp->usrsync < 12) {
+			if (scsi_mode != SMODE_SE)
+				ncr_negotiate(np, tp);
+			else
+				++oversync;
+		}
+	}
+
+	if (oversync)
+		ncr_start_reset(np, 2);
+
+	return oversync;
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+**	SCSI parity errors are handled by the SCSI script.
+**	So, we just print some message.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (ncb_p np)
+{
+	printf("%s: SCSI parity error detected\n", ncr_name(np));
+	return 0;
+}
+
+/*==========================================================
+**
 **
 **	ncr chip exception handler for phase errors.
 **
@@ -6538,22 +6562,18 @@
 
 	/*
 	**	Take into account dma fifo and various buffers and latches,
-	**	only if the interrupted phase in an OUTPUT phase.
+	**	only if the interrupted phase was DATA OUT.
 	*/
 
-	if ((cmd & 1) == 0) {
+	if ((cmd & 7) == 0) {
 		u_char	ctest5, ss0, ss2;
 		u_short	delta;
 
-		if (!(INB(nc_dstat) & DFE)) {
-			ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
-			if (ctest5 & DFS)
-				delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
-			else
-				delta=(INB (nc_dfifo) - rest) & 0x7f;
-		} else {
-			delta = 0;
-		}
+		ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+		if (ctest5 & DFS)
+			delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+		else
+			delta=(INB (nc_dfifo) - rest) & 0x7f;
 
 		/*
 		**	The data in the dma fifo has not been transfered to
@@ -6582,9 +6602,10 @@
 	} else	{
 		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
 			printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
-		if (!(INB(nc_dstat) & DFE))
-			printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n",
-				cmd&7, sbcl&7, rest);
+		if ((cmd & 7) != 1) {
+			OUTONB (nc_ctest3, CLF );
+			OUTB (nc_stest3, TE|CSF);
+		}
 	}
 
 	/*
@@ -6660,7 +6681,7 @@
 	};
 
 	/*
-	**	if old phase not dataphase, leave here.
+	**	check cmd against assumed interrupted script command.
 	*/
 
 	if (cmd != (vdsp[0] >> 24)) {
@@ -6670,6 +6691,18 @@
 		
 		return;
 	}
+
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if ((cmd & 7) == 1 && np->assert_atn) {
+		np->assert_atn = 0;
+		OUTONB(nc_socl, CATN);
+	}
+#endif
+
+	/*
+	**	if old phase not dataphase, leave here.
+	*/
+
 	if (cmd & 0x06) {
 		PRINT_ADDR(cp->cmd);
 		printf ("phase change %x-%x %d@%08x resid=%d.\n",
@@ -6712,7 +6745,10 @@
 	*/
 	np->profile.num_break++;
 	OUTL (nc_temp, vtophys (newcmd));
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	if ((cmd & 7) == 0)
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	else
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
 }
 
 /*==========================================================
@@ -6778,15 +6814,24 @@
 	}
 
 	switch (num) {
+		u_long endp;
 	case SIR_DATA_IO_IS_OUT:
+	case SIR_DATA_IO_IS_IN:
 /*
-**	We did not guess the direction of transfer. We assumed DATA IN,
-**	but the the target drove DATA OUT.
-**	We have to patch the script context with DATA OUT context and 
-**	restart processing at data out script address.
-*/
-		cp->phys.header.savep	= NCB_SCRIPTH_PHYS (np, data_out);
-		cp->phys.header.goalp	= cp->phys.header.savep +20 +cp->segments*16;
+**	We did not guess the direction of transfer. We have to wait for 
+**	actual data direction driven by the target before setting 
+**	pointers. We must patch the global header too.
+*/
+		if (num == SIR_DATA_IO_IS_OUT) {
+			endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+			cp->phys.header.goalp = endp + 8;
+			cp->phys.header.savep = endp - cp->segments*16;
+		} else {
+			endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
+			cp->phys.header.goalp = endp + 8;
+			cp->phys.header.savep = endp - cp->segments*16;
+		}
+
 		cp->phys.header.lastp	= cp->phys.header.savep;
 		np->header.savep	= cp->phys.header.savep;
 		np->header.goalp	= cp->phys.header.goalp;
@@ -7276,6 +7321,7 @@
 			(unsigned) np->header.goalp);
 		break;
 
+#if 0   /* This stuff does not work */
 /*--------------------------------------------------------------------
 **
 **	Processing of a "S_QUEUE_FULL" status.
@@ -7353,6 +7399,7 @@
 		printf ("%s: queue empty.\n", ncr_name (np));
 		np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
 		break;
+#endif   /* This stuff does not work */
 	};
 
 out:
@@ -7362,7 +7409,7 @@
 /*==========================================================
 **
 **
-**	Acquire a control block
+**	Aquire a control block
 **
 **
 **==========================================================
@@ -7496,10 +7543,10 @@
 		tp->jump_tcb.l_cmd   = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
 		tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
 
-		tp->getscr[0] = SCR_COPY (1);
+		tp->getscr[0] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
 		tp->getscr[1] = vtophys (&tp->sval);
 		tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
-		tp->getscr[3] = SCR_COPY (1);
+		tp->getscr[3] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
 		tp->getscr[4] = vtophys (&tp->wval);
 		tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
 
@@ -7712,12 +7759,15 @@
 	int segment	= 0;
 	int use_sg	= (int) cmd->use_sg;
 
+#if 0
 	bzero (cp->phys.data, sizeof (cp->phys.data));
+#endif
 	data		= cp->phys.data;
 	cp->data_len	= 0;
 
 	if (!use_sg) {
 		if (cmd->request_bufflen) {
+			data = &data[MAX_SCATTER - 1];
 			data[0].addr	= vtophys(cmd->request_buffer);
 			data[0].size	= cmd->request_bufflen;
 			cp->data_len	= data[0].size;
@@ -7727,6 +7777,7 @@
 	else if (use_sg <= MAX_SCATTER) {
 		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
 
+		data = &data[MAX_SCATTER - use_sg];
 		while (segment < use_sg) {
 			data[segment].addr = vtophys(scatter[segment].address);
 			data[segment].size = scatter[segment].length;
@@ -7753,7 +7804,9 @@
 */
 
 #ifndef NCR_IOMAPPED
+__initfunc(
 static int ncr_regtest (struct ncb* np)
+)
 {
 	register volatile u_long data;
 	/*
@@ -7777,7 +7830,9 @@
 }
 #endif
 
+__initfunc(
 static int ncr_snooptest (struct ncb* np)
+)
 {
 	u_long	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
 	int	i;
@@ -7871,7 +7926,7 @@
 **==========================================================
 */
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 
 /*
 **	Compute the difference in jiffies ticks.
@@ -7883,7 +7938,7 @@
 #define PROFILE  cp->phys.header.stamp
 static	void ncb_profile (ncb_p np, ccb_p cp)
 {
-	int co, da, st, en, di, se, post,work,disc;
+	int co, st, en, di, se, post,work,disc;
 	u_long diff;
 
 	PROFILE.end = jiffies;
@@ -7891,9 +7946,6 @@
 	st = ncr_delta (PROFILE.start,PROFILE.status);
 	if (st<0) return;	/* status  not reached  */
 
-	da = ncr_delta (PROFILE.start,PROFILE.data);
-	if (da<0) return;	/* No data transfer phase */
-
 	co = ncr_delta (PROFILE.start,PROFILE.command);
 	if (co<0) return;	/* command not executed */
 
@@ -7930,7 +7982,7 @@
 }
 #undef PROFILE
 
-#endif /* SCSI_NCR_PROFILE */
+#endif /* SCSI_NCR_PROFILE_SUPPORT */
 
 /*==========================================================
 **
@@ -7991,7 +8043,7 @@
 /*==========================================================
 **
 **	Determine the ncr's clock frequency.
-**	This is important for the negotiation
+**	This is essential for the negotiation
 **	of the synchronous transfer rate.
 **
 **==========================================================
@@ -7999,20 +8051,53 @@
 **	Note: we have to return the correct value.
 **	THERE IS NO SAVE DEFAULT VALUE.
 **
-**	We assume that all NCR based boards are delivered
-**	with a 40Mhz clock. Because we have to divide
-**	by an integer value greater than 3, only clock
-**	frequencies of 40Mhz (/4) or 50MHz (/5) permit
-**	the FAST-SCSI rate of 10MHz.
+**	Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+**	53C860 and 53C875 rev. 1 support fast20 transfers but 
+**	do not have a clock doubler and so are provided with a 
+**	80 MHz clock. All other fast20 boards incorporate a doubler 
+**	and so should be delivered with a 40 MHz clock.
+**	The future fast40 chips (895/895) use a 40 Mhz base clock 
+**	and provide a clock quadrupler (160 Mhz). The code below 
+**	tries to deal as cleverly as possible with all this stuff.
 **
 **----------------------------------------------------------
 */
 
 /*
+ *	Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+	if (np->multiplier < 2) {
+		OUTB(nc_scntl3,	scntl3);
+		return;
+	}
+
+	if (bootverbose >= 2)
+		printf ("%s: enabling clock multiplier\n", ncr_name(np));
+
+	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
+	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
+		int i = 20;
+		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+			DELAY(20);
+		if (!i)
+			printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+	} else			/* Wait 20 micro-seconds for doubler	*/
+		DELAY(20);
+	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
+	OUTB(nc_scntl3,	scntl3);
+	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
+	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
+}
+
+
+/*
  *	calculate NCR SCSI clock frequency (in KHz)
  */
-static unsigned
-ncrgetfreq (ncb_p np, int gen)
+__initfunc(
+static unsigned ncrgetfreq (ncb_p np, int gen)
+)
 {
 	unsigned ms = 0;
 
@@ -8058,38 +8143,11 @@
 }
 
 /*
- *	Select NCR SCSI clock frequency
- */
-static void ncr_selectclock(ncb_p np, u_char scntl3)
-{
-	if (np->multiplier < 2) {
-		OUTB(nc_scntl3,	scntl3);
-		return;
-	}
-
-	if (bootverbose >= 2)
-		printf ("%s: enabling clock multiplier\n", ncr_name(np));
-
-	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
-	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
-		int i = 20;
-		while (!(INB(nc_stest4) & 0x20) && --i > 0)
-			DELAY(20);
-		if (!i)
-			printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
-	} else			/* Wait 20 micro-seconds for doubler	*/
-		DELAY(20);
-	OUTB(nc_stest3, 0x20);		/* Halt the scsi clock		*/
-	OUTB(nc_scntl3,	scntl3);
-	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
-	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
-}
-
-
-/*
  *	Get/probe NCR SCSI clock frequency
  */
+__initfunc(
 static void ncr_getclock (ncb_p np, int mult)
+)
 {
 	unsigned char scntl3 = INB(nc_scntl3);
 	unsigned char stest1 = INB(nc_stest1);
@@ -8151,58 +8209,14 @@
 	np->ns_sync	= 25;
 
 	if	(f1 >= 160000) {
-		if (driver_setup.ultra_scsi) np->ns_sync = 10;
-		np->rv_scntl3 = 7;
+		if	(np->features & _F_ULTRA2)	np->ns_sync = 10;
+		else if	(np->features & _F_ULTRA)	np->ns_sync = 12;
 	}
 	else if	(f1 >= 80000) {
-		if (driver_setup.ultra_scsi) np->ns_sync = 12;
-		np->rv_scntl3 = 5;
-	}
-	else {
-		np->rv_scntl3 = 3;
-	}
-
-	if (bootverbose > 1) {
-		printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
-			ncr_name(np), scntl3, np->rv_scntl3);
+		if (np->features & _F_ULTRA)		np->ns_sync = 12;
 	}
 }
 
-/*
-**	Save some features set by bios
-**
-**	DMODE   0xce
-**		0x02	burst op-code fetch
-**		0x04	enable read multiple
-**		0x08	enable read line
-**		0xc0	burst length 16/8/2
-**	DCNTL   0xa8
-**		0x08	totem pole irq
-**		0x20	enable pre-fetch
-**		0x80	enable cache line size
-**	CTEST3  0x01
-**		0x01	set write and invalidate
-**	CTEST4  0x80
-**		0x80	burst disabled
-**	CTEST5  0x24
-**		0x20	large dma fifo 		(875 and 895 only)
-**		0x04	burst len 32/64/128	(875 and 895 only)
-**	GPCNTL	    	general purpose control register
-**	STEST2	0x20	differential mode
-*/
-
-static void ncr_save_bios_setting(ncb_p np)
-{
-	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
-	np->sv_dmode	= INB(nc_dmode)  & 0xce;
-	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
-	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
-	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
-	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
-	np->sv_gpcntl	= INB(nc_gpcntl);
-	np->sv_stest2	= INB(nc_stest2) & 0x20;
-}
-
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
 
 #ifndef uchar
@@ -8224,8 +8238,11 @@
 ** ---------------------------------------------------------------------
 */
 
+__initfunc(
 void ncr53c8xx_setup(char *str, int *ints)
+)
 {
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
 	char *pv;
 	int val;
@@ -8295,6 +8312,8 @@
 			driver_setup.diff_support= val;
 		else if	(!strncmp(cur, "irqm:", 5))
 			driver_setup.irqm	= val;
+		else if	(!strncmp(cur, "pcifix:", 7))
+			driver_setup.pci_fix_up	= val;
 
 		else if	(!strncmp(cur, "safe:", 5) && val)
 			memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
@@ -8302,34 +8321,11 @@
 		if ((cur = strchr(cur, ',')) != NULL)
 			++cur;
 	}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
 }
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-	     uchar bus, uchar device_fn, int options);
-
-/*
-**   NCR53C8XX devices description table
-*/
-
-static struct {
-     ushort pci_device_id;
-     int chip;
-     int max_revision;
-     int min_revision;
-} pci_chip_ids[] = { 
-     {PCI_DEVICE_ID_NCR_53C810,   810, -1, -1}, 
-/*   {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */
-     {PCI_DEVICE_ID_NCR_53C815,   815, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C820,   820, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C825,   825, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C860,   860, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C875,   875, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C885,   885, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C895,   895, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C896,   896, -1, -1}
-};
-
-#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+	     uchar bus, uchar device_fn);
 
 /*
 **   Linux entry point for NCR53C8XX devices detection routine.
@@ -8343,16 +8339,12 @@
 **   Returns the number of boards successfully attached.
 */
 
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+__initfunc(
+static void ncr_print_driver_setup(void)
+)
 {
-     int i, j;
-     int count = 0;			/* Number of boards detected */
-     uchar pci_bus, pci_device_fn;
-     short pci_index;	/* Device index to PCI BIOS calls */
-
 #define YesNo(y)	y ? 'y' : 'n'
-    if (bootverbose >= 2) {
-         printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+	printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
 			YesNo(driver_setup.disconnection),
 			YesNo(driver_setup.special_features),
 			YesNo(driver_setup.ultra_scsi),
@@ -8361,7 +8353,7 @@
 			driver_setup.burst_max,
 			YesNo(driver_setup.max_wide),
 			driver_setup.diff_support);
-         printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+	printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
 			YesNo(driver_setup.master_parity),
 			YesNo(driver_setup.scsi_parity),
 			YesNo(driver_setup.force_sync_nego),
@@ -8370,10 +8362,30 @@
 			YesNo(driver_setup.led_pin),
 			driver_setup.settle_delay,
 			driver_setup.irqm);
-   }
 #undef YesNo
+}
+
+/*
+**   NCR53C8XX devices description table and chip ids list.
+*/
+
+static ncr_chip	ncr_chip_table[] __initdata	= SCSI_NCR_CHIP_TABLE;
+static ushort	ncr_chip_ids[]   __initdata	= SCSI_NCR_CHIP_IDS;
+
+__initfunc(
+int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+)
+{
+	int i, j;
+	int chips;
+	int count = 0;
+	uchar bus, device_fn;
+	short index;
+
+	if (bootverbose >= 2)
+		ncr_print_driver_setup();
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	ncr_debug = driver_setup.debug;
 #endif
 
@@ -8384,21 +8396,21 @@
 # endif
 #endif
 
-     if (pcibios_present()) {
-	  for (j = 0; j < NPCI_CHIP_IDS; ++j) {
-	       i = driver_setup.reverse_probe ? NPCI_CHIP_IDS-1 - j : j;
-	       for (pci_index = 0;
-		    !pcibios_find_device(PCI_VENDOR_ID_NCR, 
-					 pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
-					 &pci_device_fn);
-                    ++pci_index)
-		    if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip, 
-			      pci_bus, pci_device_fn, /* no options */ 0))
-		    ++count;
-	 }
-     }
+	if (!pcibios_present())
+		return 0;
 
-     return count;
+	chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]);
+	for (j = 0; j < chips ; ++j) {
+		i = driver_setup.reverse_probe ? chips-1 - j : j;
+		for (index = 0; ; index++) {
+			if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+						index, &bus, &device_fn))
+				break;
+			if (!ncr53c8xx_pci_init(tpnt, count, bus, device_fn))
+				++count;
+		}
+	}
+	return count;
 }
 
 
@@ -8407,103 +8419,165 @@
 **   try yo attach it.
 */
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-		    uchar bus, uchar device_fn, int options)
-{
-     ushort vendor_id, device_id, command;
+__initfunc(
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit,
+			      uchar bus, uchar device_fn)
+)
+{
+	ushort vendor_id, device_id, command;
+	uchar cache_line_size, latency_timer;
+	uchar irq, revision;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-     uint base, io_port; 
+	uint base, io_port; 
 #else
-     ulong base, io_port; 
+	ulong base, io_port; 
 #endif
-     uchar irq, revision;
-     int error, expected_chip;
-     int expected_id = -1, max_revision = -1, min_revision = -1;
-     int i;
-
-     printk("ncr53c8xx: at PCI bus %d, device %d, function %d\n",
-	    bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
-
-     if (!pcibios_present()) {
-	  printk("ncr53c8xx: not initializing due to lack of PCI BIOS,\n");
-	  return -1;
-     }
-
-     if ((error = pcibios_read_config_word( bus, device_fn, PCI_VENDOR_ID,      &vendor_id)) ||
-	 (error = pcibios_read_config_word( bus, device_fn, PCI_DEVICE_ID,      &device_id)) ||
-	 (error = pcibios_read_config_word( bus, device_fn, PCI_COMMAND,        &command))   ||
-	 (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, &io_port))   || 
-	 (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))      ||
-	 (error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION, &revision))  ||
-	 (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE, &irq))) {
-	  printk("ncr53c8xx: error %s not initializing due to error reading configuration space\n",
-		 pcibios_strerror(error));
-	  return -1;
-     }
+	int i, error;
+	ncr_chip ncrchip, *chip;
 
-     if (vendor_id != PCI_VENDOR_ID_NCR) {
-	  printk("ncr53c8xx: not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id);
-	  return -1;
-     }
+	printk("ncr53c8xx: at PCI bus %d, device %d, function %d\n",
+		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+	/*
+	 * Read info from the PCI config space
+	 */
+	if (
+(error=pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id))	||
+(error=pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id))	||
+(error=pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command))		||
+(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,&io_port))	|| 
+(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))	||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION,&revision))	||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq))	||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, &cache_line_size)) ||
+(error=pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer))
+	)
+		goto err_pcibios;
 
+	/*
+	 *	Check if the chip is supported
+	 */
+	chip = 0;
+	for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+		if (device_id != ncr_chip_table[i].device_id)
+			continue;
+		if (revision > ncr_chip_table[i].revision_id)
+			continue;
+		chip = &ncrchip;
+		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
+		chip->revision_id = revision;
+		break;
+	}
+	if (!chip) {
+		printk("ncr53c8xx: not initializing, device not supported\n");
+		return -1;
+	}
 
-     if (command & PCI_COMMAND_IO) { 
-	  if ((io_port & 3) != 1) {
-	       printk("ncr53c8xx : disabling I/O mapping since base address 0 (0x%x)\n"
-		      "            bits 0..1 indicate a non-IO mapping\n", (int) io_port);
-	       io_port = 0;
-	  }
-	  else
-	       io_port &= PCI_BASE_ADDRESS_IO_MASK;
-     }
-     else
-	  io_port = 0;
+	/*
+	 * Check availability of IO space, memory space and master capability.
+	 */
+	if (command & PCI_COMMAND_IO) { 
+		if ((io_port & 3) != 1) {
+			printk("ncr53c8xx: disabling I/O mapping since base address 0 (0x%x)\n"
+				"           bits 0..1 indicate a non-IO mapping\n", (int) io_port);
+			io_port = 0;
+		}
+		else
+			io_port &= PCI_BASE_ADDRESS_IO_MASK;
+	}
+	else
+		io_port = 0;
 
-     if (command & PCI_COMMAND_MEMORY) {
-	  if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-	       printk("ncr53c8xx: disabling memory mapping since base address 1\n"
-		      "            contains a non-memory mapping\n");
-	       base = 0;
-	  }
-	  else 
-	       base &= PCI_BASE_ADDRESS_MEM_MASK;
-     }
-     else
-	  base = 0;
+	if (command & PCI_COMMAND_MEMORY) {
+		if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			printk("ncr53c8xx: disabling memory mapping since base address 1\n"
+				"            contains a non-memory mapping\n");
+			base = 0;
+		}
+		else 
+			base &= PCI_BASE_ADDRESS_MEM_MASK;
+	}
+	else
+		base = 0;
 	
-     if (!io_port && !base) {
-	  printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
-	  return -1;
-     }
+	if (!io_port && !base) {
+		printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
+		return -1;
+	}
+
+	if (io_port && check_region (io_port, 128)) {
+		printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
+			(int) io_port, (int) (io_port + 127));
+		return -1;
+	}
 	
-     if (!(command & PCI_COMMAND_MASTER)) {
-	  printk ("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
-	  return -1;
-     }
+	if (!(command & PCI_COMMAND_MASTER)) {
+		printk("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
+		return -1;
+	}
 
-     for (i = 0; i < NPCI_CHIP_IDS; ++i) {
-	  if (device_id == pci_chip_ids[i].pci_device_id) {
-	       max_revision  = pci_chip_ids[i].max_revision;
-	       min_revision  = pci_chip_ids[i].min_revision;
-	       expected_chip = pci_chip_ids[i].chip;
-	  }
-	  if (chip == pci_chip_ids[i].chip)
-	       expected_id = pci_chip_ids[i].pci_device_id;
-     }
+	/*
+	 * Remove not wished features.
+	 */
+	if (!driver_setup.special_features)
+		chip->features &= ~_F_SPECIAL_SET;
+	if (driver_setup.ultra_scsi < 2 && chip->features & _F_ULTRA2)
+		chip->features &= ~(_F_ULTRA2 | _F_ULTRA);
+	if (driver_setup.ultra_scsi < 1)
+		chip->features &= ~_F_ULTRA;
+	if (!driver_setup.max_wide)
+		chip->features &= ~_F_WIDE;
 
-     if (chip && device_id != expected_id) 
-	  printk("ncr53c8xx: warning : device id of 0x%04x doesn't\n"
-		 "            match expected 0x%04x\n",
-		  (unsigned int) device_id, (unsigned int) expected_id );
-    
-     if (io_port && check_region (io_port, 128)) {
-	  printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
-		 (int) io_port, (int) (io_port + 127));
-	  return -1;
-     }
+	/*
+	 * Try to fix up PCI config according to wished features.
+	 */
+#ifdef __i386
+	if ((driver_setup.pci_fix_up & 1) &&
+	    (chip->features & _F_CLSE) && cache_line_size == 0) {
+		extern char x86;
+		switch(x86) {
+		case 4:	cache_line_size = 4; break;
+		case 5:	cache_line_size = 8; break;
+		}
+		if (cache_line_size)
+			error = pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size);
+		if (error)
+			goto err_pcibios;
+		if (bootverbose)
+			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
+	}
+
+	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+	    (chip->features & _F_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+		command |= PCI_COMMAND_INVALIDATE;
+		error=pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		if (error)
+			goto err_pcibios;
+		if (bootverbose)
+			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
+	}
+#endif
+	/*
+	 * Remove features that will not work
+	 */
+	if ((chip->features & _F_CLSE) && cache_line_size == 0) {
+		chip->features &= ~_F_CACHE_SET;
+		printk("ncr53c8xx: PCI_CACHE_LINE_SIZE not set, features based on CACHE LINE SIZE not used.\n");
+	}
+
+	if ((chip->features & _F_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+		chip->features &= ~_F_WRIE;
+		printk("ncr53c8xx: PCI_COMMAND_INVALIDATE not set, WRITE AND INVALIDATE not used\n");
+	}
 
-     return ncr_attach (tpnt, unit, device_id, revision, chip, base, io_port, 
-		       (int) irq, bus, (uchar) device_fn);
+	/*
+	 * Try to attach the controller
+	 */
+	return ncr_attach (tpnt, unit, chip, base, io_port, (int) irq, 
+			bus, (uchar) device_fn);
+err_pcibios:
+	printk("ncr53c8xx: error %s reading configuration space\n",
+		pcibios_strerror(error));
+	return -1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
@@ -8527,7 +8601,7 @@
 			device->queue_depth = 1;
 #endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
 	device->id, device->lun, device->queue_depth);
 #endif
@@ -8543,19 +8617,19 @@
 int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
      int sts;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_queue_command\n");
 #endif
 
      if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
 	  cmd->result = ScsiResult(sts, 0);
 	  done(cmd);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command not queued - result=%d\n", sts);
 #endif
           return sts;
      }
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command successfully queued\n");
 #endif
      return sts;
@@ -8573,8 +8647,13 @@
 {
      struct Scsi_Host *host;
      struct host_data *host_data;
+#if 0
+     u_long flags;
+
+     save_flags(flags); cli();
+#endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : interrupt received\n");
 #endif
 
@@ -8583,12 +8662,20 @@
 	       host_data = (struct host_data *) host->hostdata;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 #   ifdef SCSI_NCR_SHARE_IRQ
-               if (dev_id == host_data->ncb)
+               if (dev_id == host_data->ncb) {
+#else
+               if (1) {
 #   endif
 #endif
-	       ncr_intr(host_data->ncb);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+	            ncr_exception(host_data->ncb);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+               }
 	  }
      }
+#if 0
+     restore_flags(flags);
+#endif
 }
 
 /*
@@ -8696,7 +8783,7 @@
 int ncr53c8xx_release(struct Scsi_Host *host)
 {
      struct host_data *host_data;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : release\n");
 #endif
 
@@ -8847,6 +8934,8 @@
 **=========================================================================
 */
 
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
+
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 #define digit_to_bin(c)	((c) - '0')
 #define is_space(c)	((c) == ' ' || (c) == '\t')
@@ -8928,6 +9017,10 @@
 		uc->cmd = UC_SETFLAG;
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	else if	((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
+		uc->cmd = UC_DEBUG_ERROR_RECOVERY;
+#endif
 	else
 		arg_len = 0;
 
@@ -9028,13 +9121,30 @@
 			ptr += arg_len; len -= arg_len;
 		}
 		break;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	case UC_DEBUG_ERROR_RECOVERY:
+		SKIP_SPACES(1);
+		if	((arg_len = is_keyword(ptr, len, "sge")))
+			uc->data = 1;
+		else if	((arg_len = is_keyword(ptr, len, "abort")))
+			uc->data = 2;
+		else if	((arg_len = is_keyword(ptr, len, "reset")))
+			uc->data = 3;
+		else if	((arg_len = is_keyword(ptr, len, "parity")))
+			uc->data = 4;
+		else if	((arg_len = is_keyword(ptr, len, "none")))
+			uc->data = 0;
+		else
+			return -EINVAL;
+		ptr += arg_len; len -= arg_len;
+		break;
+#endif
 	default:
 		break;
 	}
 
 	if (len)
 		return -EINVAL;
-#ifdef SCSI_NCR_USER_COMMAND
 	else {
 		long flags;
 
@@ -9042,10 +9152,13 @@
 		ncr_usercmd (np);
 		restore_flags(flags);
 	}
-#endif
 	return length;
 }
 
+#endif	/* SCSI_NCR_USER_COMMAND_SUPPORT */
+
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
 struct info_str
 {
 	char *buffer;
@@ -9104,7 +9217,7 @@
 	info.pos	= 0;
 
 	copy_info(&info, "General information:\n");
-	copy_info(&info, "  Chip NCR53C%03d, ",	np->chip);
+	copy_info(&info, "  Chip NCR53C%s, ",	np->chip_name);
 	copy_info(&info, "device id 0x%x, ",	np->device_id);
 	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
 
@@ -9124,7 +9237,7 @@
 		copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
 	}
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	copy_info(&info, "Profiling information:\n");
 	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
 	copy_info(&info, "  %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
@@ -9141,6 +9254,8 @@
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
+#endif /* SCSI_NCR_USER_INFO_SUPPORT */
+
 /*
 **	Entry point of the scsi proc fs of the driver.
 **	- func = 0 means read  (returns profile data)
@@ -9171,19 +9286,25 @@
 		return -EINVAL;
 
 	if (func) {
+#ifdef	SCSI_NCR_USER_COMMAND_SUPPORT
 		retv = ncr_user_command(ncb, buffer, length);
-#ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: retv=%d\n", retv);
+#else
+		retv = -EINVAL;
 #endif
 	}
 	else {
 		if (start)
 			*start = buffer;
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
 		retv = ncr_host_info(ncb, buffer, offset, length);
+#else
+		retv = -EINVAL;
+#endif
 	}
 
 	return retv;
 }
+
 
 /*=========================================================================
 **	End of proc file system stuff
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.1.36/linux/drivers/scsi/ncr53c8xx.h	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/ncr53c8xx.h	Tue May 13 21:58:42 1997
@@ -45,36 +45,7 @@
 /*
 **	Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 1.18f"
- 
-/*
-**	If SCSI_NCR_SETUP_SPECIAL_FEATURES is defined,
-**	the driver enables or not the following features according to chip id 
-**	revision id:
-**	DMODE   0xce
-**		0x02	burst op-code fetch
-**		0x04	enable read multiple
-**		0x08	enable read line
-**		0xc0	burst length 16/8/2
-**	DCNTL   0xa0
-**		0x20	enable pre-fetch
-**		0x80	enable cache line size
-**	CTEST3  0x01
-**		0x01	set write and invalidate
-**	CTEST4  0x80
-**		0x80	burst disabled
-**	CTEST5  0x24	(825a and 875 only)
-**		0x04	burst 128
-**		0x80	large dma fifo
-**
-**	If SCSI_NCR_TRUST_BIOS_SETTING is defined, the driver will use the 
-**	initial value of corresponding bit fields, assuming they have been 
-**	set by the SDMS BIOS.
-**	When Linux is booted from another O/S, these assertion is false and 
-**	the driver will not be able to guess it. 
-*/
-
-/*********** LINUX SPECIFIC SECTION ******************/
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.1b"
 
 /*
 **	Check supported Linux versions
@@ -97,28 +68,6 @@
 #define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
 #endif
 
-#if !defined(VERSION)
-#define VERSION		((LINUX_VERSION_CODE >> 16) & 0xff)
-#define PATCHLEVEL	((LINUX_VERSION_CODE >> 8)  & 0xff)
-#define SUBLEVEL	((LINUX_VERSION_CODE >> 0)  & 0xff)
-#endif
-
-#if	VERSION == 0 || VERSION > 3
-#	error Only Linux version 1 and probable 2 or 3 supported.
-#endif
-
-#if	VERSION == 1 && PATCHLEVEL == 2
-#	if	SUBLEVEL != 13
-#		error Only sublevel 13 of Linux 1.2 is supported.
-#	endif
-#endif
-
-#if	VERSION == 1 && PATCHLEVEL == 3
-#	if	SUBLEVEL < 45
-#		error Only sublevels >=45 of Linux 1.3 are supported.
-#	endif
-#endif
-
 /*
 **	Normal IO or memory mapped IO.
 **
@@ -139,6 +88,20 @@
 #	define SCSI_NCR_SHARE_IRQ
 #endif
 
+/*
+**	If you want a driver as small as possible, donnot define the 
+**	following options.
+*/
+
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+#ifdef	SCSI_NCR_PROC_INFO_SUPPORT
+#	define	SCSI_NCR_PROFILE_SUPPORT
+#	define	SCSI_NCR_USER_COMMAND_SUPPORT
+#	define	SCSI_NCR_USER_INFO_SUPPORT
+/* #	define	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
+#endif
+
 /* ---------------------------------------------------------------------
 ** Take into account kernel configured parameters.
 ** Most of these options can be overridden at startup by a command line.
@@ -208,14 +171,6 @@
 #endif
 
 /*
- * Default sync to 0 will force asynchronous at startup
- */
-#ifdef	CONFIG_SCSI_FORCE_ASYNCHRONOUS
-#undef	SCSI_NCR_SETUP_DEFAULT_SYNC
-#define SCSI_NCR_SETUP_DEFAULT_SYNC	(255)
-#endif
-
-/*
  * Disallow disconnections at boot-up
  */
 #ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -291,57 +246,6 @@
 #endif
 
 /*
-**	Initial setup.
-**	Can be overriden at startup by a command line.
-*/
-#define SCSI_NCR_DRIVER_SETUP			\
-{						\
-	SCSI_NCR_SETUP_MASTER_PARITY,		\
-	SCSI_NCR_SETUP_SCSI_PARITY,		\
-	SCSI_NCR_SETUP_DISCONNECTION,		\
-	SCSI_NCR_SETUP_SPECIAL_FEATURES,	\
-	SCSI_NCR_SETUP_ULTRA_SCSI,		\
-	SCSI_NCR_SETUP_FORCE_SYNC_NEGO,		\
-	0,					\
-	1,					\
-	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
-	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
-	0x00,					\
-	7,					\
-	SCSI_NCR_SETUP_LED_PIN,			\
-	1,					\
-	SCSI_NCR_SETUP_SETTLE_TIME,		\
-	SCSI_NCR_SETUP_DIFF_SUPPORT,		\
-	0					\
-}
-
-/*
-**	Boot fail safe setup.
-**	Override initial setup from boot command line:
-**	ncr53c8xx=safe:y
-*/
-#define SCSI_NCR_DRIVER_SAFE_SETUP		\
-{						\
-	0,					\
-	1,					\
-	0,					\
-	0,					\
-	0,					\
-	0,					\
-	0,					\
-	2,					\
-	0,					\
-	255,					\
-	0x00,					\
-	255,					\
-	0,					\
-	0,					\
-	10,					\
-	1,					\
-	1					\
-}
-
-/*
 **	Define Scsi_Host_Template parameters
 **
 **	Used by hosts.c and ncr53c8xx.c with module configuration.
@@ -399,6 +303,198 @@
 #ifndef HOSTS_C
 
 /*
+**	NCR53C8XX Device Ids
+*/
+
+#ifndef PCI_DEVICE_ID_NCR_53C810
+#define PCI_DEVICE_ID_NCR_53C810 1
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C810AP
+#define PCI_DEVICE_ID_NCR_53C810AP 5
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C815
+#define PCI_DEVICE_ID_NCR_53C815 4
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C820
+#define PCI_DEVICE_ID_NCR_53C820 2
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C825
+#define PCI_DEVICE_ID_NCR_53C825 3
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C860
+#define PCI_DEVICE_ID_NCR_53C860 6
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875
+#define PCI_DEVICE_ID_NCR_53C875 0xf
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875J
+#define PCI_DEVICE_ID_NCR_53C875J 0x8f
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C885
+#define PCI_DEVICE_ID_NCR_53C885 0xd
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C895
+#define PCI_DEVICE_ID_NCR_53C895 0xc
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C896
+#define PCI_DEVICE_ID_NCR_53C896 0xb
+#endif
+
+/*
+**   NCR53C8XX devices features table.
+*/
+typedef struct {
+	unsigned short	device_id;
+	unsigned short	revision_id;
+	char	*name;
+	unsigned char	burst_max;
+	unsigned char	offset_max;
+	unsigned char	nr_divisor;
+	unsigned int	features;
+#define _F_LED0		(1<<0)
+#define _F_WIDE		(1<<1)
+#define _F_ULTRA	(1<<2)
+#define _F_ULTRA2	(1<<3)
+#define _F_DBLR		(1<<4)
+#define _F_QUAD		(1<<5)
+#define _F_ERL		(1<<6)
+#define _F_CLSE		(1<<7)
+#define _F_WRIE		(1<<8)
+#define _F_ERMP		(1<<9)
+#define _F_BOF		(1<<10)
+#define _F_DFS		(1<<11)
+#define _F_PFEN		(1<<12)
+#define _F_LDSTR	(1<<13)
+#define _F_RAM		(1<<14)
+#define _F_CLK80	(1<<15)
+#define _F_CACHE_SET	(_F_ERL|_F_CLSE|_F_WRIE|_F_ERMP)
+#define _F_SCSI_SET	(_F_WIDE|_F_ULTRA|_F_ULTRA2|_F_DBLR|_F_QUAD|F_CLK80)
+#define _F_SPECIAL_SET	(_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM)
+} ncr_chip;
+
+#define SCSI_NCR_CHIP_TABLE						\
+{									\
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810",  4,  8, 4,			\
+ _F_ERL}								\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4,  8, 4,			\
+ _F_CACHE_SET|_F_LDSTR|_F_PFEN|_F_BOF}					\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815",  4,  8, 4,			\
+ _F_ERL|_F_BOF}								\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C820, 0xff, "820",  4,  8, 4,			\
+ _F_WIDE|_F_ERL}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,			\
+ _F_WIDE|_F_ERL|_F_BOF}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7,  8, 4,			\
+ _F_WIDE|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}		\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  7, 16, 5,			\
+ _F_WIDE|_F_ULTRA|_F_CLK80|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  7, 16, 5,			\
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J",  7, 16, 5,			\
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  7, 16, 5,			\
+ _F_WIDE|_F_ULTRA|_F_DBLR|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  7, 31, 7,			\
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  7, 31, 7,			\
+ _F_WIDE|_F_ULTRA|_F_ULTRA2|_F_QUAD|_F_CACHE_SET|_F_BOF|_F_DFS|_F_LDSTR|_F_PFEN|_F_RAM}	\
+}
+
+/*
+ * List of supported NCR chip ids
+ */
+#define SCSI_NCR_CHIP_IDS		\
+{					\
+	PCI_DEVICE_ID_NCR_53C810,	\
+	PCI_DEVICE_ID_NCR_53C815,	\
+	PCI_DEVICE_ID_NCR_53C820,	\
+	PCI_DEVICE_ID_NCR_53C825,	\
+	PCI_DEVICE_ID_NCR_53C860,	\
+	PCI_DEVICE_ID_NCR_53C875,	\
+	PCI_DEVICE_ID_NCR_53C875J,	\
+	PCI_DEVICE_ID_NCR_53C885,	\
+	PCI_DEVICE_ID_NCR_53C895,	\
+	PCI_DEVICE_ID_NCR_53C896	\
+}
+
+/*
+**	Initial setup.
+**	Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP			\
+{						\
+	SCSI_NCR_SETUP_MASTER_PARITY,		\
+	SCSI_NCR_SETUP_SCSI_PARITY,		\
+	SCSI_NCR_SETUP_DISCONNECTION,		\
+	SCSI_NCR_SETUP_SPECIAL_FEATURES,	\
+	SCSI_NCR_SETUP_ULTRA_SCSI,		\
+	SCSI_NCR_SETUP_FORCE_SYNC_NEGO,		\
+	0,					\
+	0,					\
+	1,					\
+	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
+	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
+	0x00,					\
+	7,					\
+	SCSI_NCR_SETUP_LED_PIN,			\
+	1,					\
+	SCSI_NCR_SETUP_SETTLE_TIME,		\
+	SCSI_NCR_SETUP_DIFF_SUPPORT,		\
+	0					\
+}
+
+/*
+**	Boot fail safe setup.
+**	Override initial setup from boot command line:
+**	ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP		\
+{						\
+	0,					\
+	1,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	2,					\
+	0,					\
+	255,					\
+	0x00,					\
+	255,					\
+	0,					\
+	0,					\
+	10,					\
+	1,					\
+	1					\
+}
+
+/*
 **	Define the table of target capabilities by host and target
 **
 **	If you have problems with a scsi device, note the host unit and the
@@ -486,50 +582,6 @@
 #endif
 #endif
 
-/*
-**	NCR53C8XX Device Ids
-*/
-
-#ifndef PCI_DEVICE_ID_NCR_53C810
-#define PCI_DEVICE_ID_NCR_53C810 1
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C810AP
-#define PCI_DEVICE_ID_NCR_53C810AP 5
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C815
-#define PCI_DEVICE_ID_NCR_53C815 4
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C820
-#define PCI_DEVICE_ID_NCR_53C820 2
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C825
-#define PCI_DEVICE_ID_NCR_53C825 3
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C860
-#define PCI_DEVICE_ID_NCR_53C860 6
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C875
-#define PCI_DEVICE_ID_NCR_53C875 0xf
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C885
-#define PCI_DEVICE_ID_NCR_53C885 0xd
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C895
-#define PCI_DEVICE_ID_NCR_53C895 0xc
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C896
-#define PCI_DEVICE_ID_NCR_53C896 0xb
-#endif
-
 /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
 
 /*-----------------------------------------------------------------
@@ -608,6 +660,7 @@
         #define   ILF1    0x80  /* sta: data in SIDL register msb[W]*/
         #define   ORF1    0x40  /* sta: data in SODR register msb[W]*/
         #define   OLF1    0x20  /* sta: data in SODL register msb[W]*/
+        #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
         #define   LDSC    0x02  /* sta: disconnect & reconnect      */
 
 /*10*/  u_int32    nc_dsa;	/* --> Base page                    */
@@ -680,6 +733,7 @@
 
 /*40*/  u_short   nc_sien;	/* -->: interrupt enable            */
 /*42*/  u_short   nc_sist;	/* <--: interrupt status            */
+        #define   SBMC    0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
         #define   STO     0x0400/* sta: timeout (select)            */
         #define   GEN     0x0200/* sta: timeout (general)           */
         #define   HTH     0x0100/* sta: timeout (handshake)         */
@@ -713,10 +767,17 @@
 
 /*4f*/  u_char    nc_stest3;
 	#define   TE     0x80	/* c: tolerAnt enable */
+	#define   HSC    0x20	/* c: Halt SCSI Clock */
 	#define   CSF    0x02	/* c: clear scsi fifo */
 
 /*50*/  u_short   nc_sidl;	/* Lowlevel: latched from scsi data */
 /*52*/  u_char    nc_stest4;
+	#define   SMODE  0xc0	/* SCSI bus mode      (895/6 only) */
+	#define    SMODE_HVD 0x40	/* High Voltage Differential       */
+	#define    SMODE_SE  0x80	/* Single Ended                    */
+	#define    SMODE_LVD 0xc0	/* Low Voltage Differential        */
+	#define   LCKFRQ 0x20	/* Frequency Lock (895/6 only)     */
+
 /*53*/	u_char    nc_53_;
 /*54*/  u_short   nc_sodl;	/* Lowlevel: data out to scsi data  */
 /*56*/  u_short   nc_56_;
@@ -870,10 +931,18 @@
 **	<< source_address >>
 **	<< destination_address >>
 **
+**	SCR_COPY   sets the NO FLUSH option by default.
+**	SCR_COPY_F does not set this option.
+**
+**	For chips which do not support this option,
+**	ncr_copy_and_bind() will remove this bit.
 **-----------------------------------------------------------
 */
 
-#define SCR_COPY(n) (0xc0000000 | (n))
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
 
 /*-----------------------------------------------------------
 **
@@ -979,6 +1048,7 @@
 **-----------------------------------------------------------
 */
 
+#define SCR_NO_OP        0x80000000
 #define SCR_JUMP        0x80080000
 #define SCR_JUMPR       0x80880000
 #define SCR_CALL        0x88080000
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v2.1.36/linux/drivers/scsi/scsi_proc.c	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/scsi_proc.c	Tue May 13 14:41:32 1997
@@ -11,6 +11,9 @@
  * 
  * generic command parser provided by: 
  * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ *
+ * generic_proc_info() support of xxxx_info() by:
+ * Michael A. Griffith <grif@acm.org>
  */
 
 /*
@@ -48,7 +51,9 @@
  * Used if the driver currently has no own support for /proc/scsi
  */
 int generic_proc_info(char *buffer, char **start, off_t offset, 
-		     int length, int inode, int inout)
+		     int length, int inode, int inout, 
+                     const char *(*info)(struct Scsi_Host *),
+                     struct Scsi_Host *sh)
 {
     int len, pos, begin;
 
@@ -56,8 +61,13 @@
 	return(-ENOSYS);  /* This is a no-op */
     
     begin = 0;
-    pos = len = sprintf(buffer, 
-			"The driver does not yet support the proc-fs\n");
+    if (info && sh) {
+          pos = len = sprintf(buffer, "%s\n", info(sh));
+    }
+    else {
+      pos = len = sprintf(buffer, 
+                          "The driver does not yet support the proc-fs\n");
+    }
     if(pos < offset) {
 	len = 0;
 	begin = pos;
@@ -91,7 +101,9 @@
         if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
             if(hpnt->hostt->proc_info == NULL)
                 return generic_proc_info(buffer, start, offset, length, 
-                                         hpnt->host_no, func);
+                                         hpnt->host_no, func,
+                                         hpnt->hostt->info,
+                                         hpnt);
             else
                 return(hpnt->hostt->proc_info(buffer, start, offset, 
                                               length, hpnt->host_no, func));
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.1.36/linux/drivers/scsi/scsiiom.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/scsiiom.c	Mon May 12 10:35:42 1997
@@ -0,0 +1,1540 @@
+/***********************************************************************
+ *	FILE NAME : SCSIIOM.C					       *
+ *	     BY   : C.L. Huang,    ching@tekram.com.tw		       *
+ *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
+ *		     Bus Master Host Adapter			       *
+ ***********************************************************************/
+
+
+static USHORT
+DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    USHORT ioport, rc;
+    UCHAR  bval, bval1, i, cnt;
+    PUCHAR ptr;
+    ULONG  wlval;
+
+    pSRB->TagNumber = 31;
+    ioport = pACB->IOPortBase;
+    bval = pDCB->UnitSCSIID;
+    outb(bval,ioport+Scsi_Dest_ID);
+    bval = pDCB->SyncPeriod;
+    outb(bval,ioport+Sync_Period);
+    bval = pDCB->SyncOffset;
+    outb(bval,ioport+Sync_Offset);
+    bval = pDCB->CtrlR1;
+    outb(bval,ioport+CtrlReg1);
+    bval = pDCB->CtrlR3;
+    outb(bval,ioport+CtrlReg3);
+    bval = pDCB->CtrlR4;
+    outb(bval,ioport+CtrlReg4);
+    bval = CLEAR_FIFO_CMD;	   /* Flush FIFO */
+    outb(bval,ioport+ScsiCmd);
+
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = pDCB->IdentifyMsg;
+    if( !(pDCB->SyncMode & EN_ATN_STOP) )
+    {
+	if( (pSRB->CmdBlock[0] == INQUIRY) ||
+	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+	    (pSRB->SRBFlag & AUTO_REQSENSE) )
+	{
+	    bval &= 0xBF;	/* NO disconnection */
+	    outb(bval,ioport+ScsiFifo);
+	    bval1 = SELECT_W_ATN;
+	    pSRB->SRBState = SRB_START_;
+	    if( pDCB->SyncMode & SYNC_ENABLE )
+	    {
+		if( !(pDCB->IdentifyMsg & 7) ||
+		    (pSRB->CmdBlock[0] != INQUIRY) )
+		{
+		    bval1 = SEL_W_ATN_STOP;
+		    pSRB->SRBState = SRB_MSGOUT;
+		}
+	    }
+	}
+	else
+	{
+	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    {
+		outb(bval,ioport+ScsiFifo);
+		bval = MSG_SIMPLE_QTAG;
+		outb(bval,ioport+ScsiFifo);
+		wlval = 1;
+		bval = 0;
+		while( wlval & pDCB->TagMask )
+		{
+		    wlval = wlval << 1;
+		    bval++;
+		}
+		outb(bval,ioport+ScsiFifo);
+		pDCB->TagMask |= wlval;
+		pSRB->TagNumber = bval;
+		bval1 = SEL_W_ATN2;
+		pSRB->SRBState = SRB_START_;
+	    }
+	    else
+	    {
+		outb(bval,ioport+ScsiFifo);
+		bval1 = SELECT_W_ATN;
+		pSRB->SRBState = SRB_START_;
+	    }
+	}
+
+	if( pSRB->SRBFlag & AUTO_REQSENSE )
+	{
+	    bval = REQUEST_SENSE;
+	    outb(bval,ioport+ScsiFifo);
+	    bval = pDCB->IdentifyMsg << 5;
+	    outb(bval,ioport+ScsiFifo);
+	    bval = 0;
+	    outb(bval,ioport+ScsiFifo);
+	    outb(bval,ioport+ScsiFifo);
+	    bval = sizeof(pSRB->pcmd->sense_buffer);
+	    outb(bval,ioport+ScsiFifo);
+	    bval = 0;
+	    outb(bval,ioport+ScsiFifo);
+	}
+	else
+	{
+	    cnt = pSRB->ScsiCmdLen;
+	    ptr = (PUCHAR) pSRB->CmdBlock;
+	    for(i=0; i<cnt; i++)
+	    {
+		bval = *ptr++;
+		outb(bval,ioport+ScsiFifo);
+	    }
+	}
+    }
+    else	/* ATN_STOP */
+    {
+	if( (pSRB->CmdBlock[0] == INQUIRY) ||
+	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+	    (pSRB->SRBFlag & AUTO_REQSENSE) )
+	{
+	    bval &= 0xBF;
+	    outb(bval,ioport+ScsiFifo);
+	    bval1 = SELECT_W_ATN;
+	    pSRB->SRBState = SRB_START_;
+	    if( pDCB->SyncMode & SYNC_ENABLE )
+	    {
+		if( !(pDCB->IdentifyMsg & 7) ||
+		    (pSRB->CmdBlock[0] != INQUIRY) )
+		{
+		    bval1 = SEL_W_ATN_STOP;
+		    pSRB->SRBState = SRB_MSGOUT;
+		}
+	    }
+	}
+	else
+	{
+	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    {
+		outb(bval,ioport+ScsiFifo);
+		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
+		wlval = 1;
+		bval = 0;
+		while( wlval & pDCB->TagMask )
+		{
+		    wlval = wlval << 1;
+		    bval++;
+		}
+		pDCB->TagMask |= wlval;
+		pSRB->TagNumber = bval;
+		pSRB->MsgOutBuf[1] = bval;
+		pSRB->MsgCnt = 2;
+		bval1 = SEL_W_ATN_STOP;
+		pSRB->SRBState = SRB_START_;
+	    }
+	    else
+	    {
+		outb(bval,ioport+ScsiFifo);
+		pSRB->MsgOutBuf[0] = MSG_NOP;
+		pSRB->MsgCnt = 1;
+		pSRB->SRBState = SRB_START_;
+		bval1 = SEL_W_ATN_STOP;
+	    }
+	}
+    }
+    bval = inb( ioport+Scsi_Status );
+    if( bval & INTERRUPT )
+    {
+	pSRB->SRBState = SRB_READY;
+	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
+	rc = 1;
+    }
+    else
+    {
+	pSRB->ScsiPhase = SCSI_NOP1;
+	pACB->pActiveDCB = pDCB;
+	pDCB->pActiveSRB = pSRB;
+	rc = 0;
+	outb(bval1,ioport+ScsiCmd);
+    }
+    return( rc );
+}
+
+
+#ifndef  VERSION_ELF_1_2_13
+static void
+DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void
+DC390_Interrupt( int irq, struct pt_regs *regs)
+#endif
+{
+    PACB   pACB;
+    PDCB   pDCB;
+    PSRB   pSRB;
+    USHORT ioport = 0;
+    USHORT phase, i;
+    void   (*stateV)( PACB, PSRB, PUCHAR );
+    UCHAR  istate = 0;
+    UCHAR  sstatus=0, istatus;
+
+    pACB = pACB_start;
+    if( pACB == NULL )
+	return;
+    for( i=0; i < adapterCnt; i++ )
+    {
+	if( pACB->IRQLevel == (UCHAR) irq )
+	{
+	     ioport = pACB->IOPortBase;
+	     sstatus = inb( ioport+Scsi_Status );
+	     if( sstatus & INTERRUPT )
+		 break;
+	     else
+		pACB = pACB->pNextACB;
+	}
+	else
+	{
+	    pACB = pACB->pNextACB;
+	}
+    }
+
+#ifdef DC390_DEBUG1
+	printk("sstatus=%2x,",sstatus);
+#endif
+
+    if( pACB == (PACB )-1 )
+    {
+	printk("DC390: Spurious interrupt detected!\n");
+	return;
+    }
+
+    istate = inb( ioport+Intern_State );
+    istatus = inb( ioport+INT_Status );
+
+#ifdef DC390_DEBUG1
+	printk("Istatus=%2x,",istatus);
+#endif
+
+    if(istatus &  DISCONNECTED)
+    {
+	DC390_Disconnect( pACB );
+	return;
+    }
+
+    if(istatus &  RESELECTED)
+    {
+	DC390_Reselect( pACB );
+	return;
+    }
+
+    if(istatus &  INVALID_CMD)
+    {
+	DC390_InvalidCmd( pACB );
+	return;
+    }
+
+    if(istatus &  SCSI_RESET)
+    {
+	DC390_ScsiRstDetect( pACB );
+	return;
+    }
+
+    if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+    {
+	pDCB = pACB->pActiveDCB;
+	pSRB = pDCB->pActiveSRB;
+	if( pDCB )
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+		EnableMsgOut( pACB, pSRB );
+	}
+
+	phase = (USHORT) pSRB->ScsiPhase;
+	stateV = (void *) DC390_phase0[phase];
+	stateV( pACB, pSRB, &sstatus );
+
+	pSRB->ScsiPhase = sstatus & 7;
+	phase = (USHORT) sstatus & 7;
+	stateV = (void *) DC390_phase1[phase];
+	stateV( pACB, pSRB, &sstatus );
+    }
+}
+
+
+static void
+DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   sstatus, bval;
+    USHORT  ioport;
+    PSGL    psgl;
+    ULONG   ResidCnt, xferCnt;
+
+    ioport = pACB->IOPortBase;
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & PARITY_ERR )
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    bval = inb(ioport+DMA_Status);
+	    while( !(bval & DMA_XFER_DONE) )
+		bval = inb(ioport+DMA_Status);
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+		pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+		pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else
+	{
+	    bval = inb( ioport+Current_Fifo );
+	    bval &= 0x1f;
+	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+	    ResidCnt += (ULONG) bval;
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+	}
+    }
+    bval = WRITE_DIRECTION+DMA_IDLE_CMD;
+    outb( bval, ioport+DMA_Cmd);
+}
+
+static void
+DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   sstatus, bval;
+    USHORT  i, ioport, residual;
+    PSGL    psgl;
+    ULONG   ResidCnt, xferCnt;
+    PUCHAR  ptr;
+
+
+    ioport = pACB->IOPortBase;
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & PARITY_ERR )
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    bval = inb(ioport+DMA_Status);
+	    while( !(bval & DMA_XFER_DONE) )
+		bval = inb(ioport+DMA_Status);
+
+	    bval = READ_DIRECTION+DMA_IDLE_CMD;
+	    outb( bval, ioport+DMA_Cmd);
+
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+		pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+		pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else	/* phase changed */
+	{
+	    residual = 0;
+	    bval = inb(ioport+Current_Fifo);
+	    while( bval & 0x1f )
+	    {
+		if( (bval & 0x1f) == 1 )
+		{
+		    for(i=0; i< 0x100; i++)
+		    {
+			bval = inb(ioport+Current_Fifo);
+			if( !(bval & 0x1f) )
+			    goto din_1;
+			else if( i == 0x0ff )
+			{
+			    residual = 1;   /* ;1 residual byte */
+			    goto din_1;
+			}
+		    }
+		}
+		else
+		    bval = inb(ioport+Current_Fifo);
+	    }
+din_1:
+	    bval = READ_DIRECTION+DMA_BLAST_CMD;
+	    outb(bval, ioport+DMA_Cmd);
+	    for(i=0; i<0x8000; i++)
+	    {
+		bval = inb(ioport+DMA_Status);
+		if(bval & BLAST_COMPLETE)
+		    break;
+	    }
+	    bval = READ_DIRECTION+DMA_IDLE_CMD;
+	    outb(bval, ioport+DMA_Cmd);
+
+	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+
+	    if( residual )
+	    {
+		bval = inb(ioport+ScsiFifo);	    /* get residual byte */
+#ifndef VERSION_ELF_1_2_13
+		ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+#else
+		ptr = (PUCHAR) pSRB->SGPhysAddr;
+#endif
+		*ptr = bval;
+		pSRB->SGPhysAddr++;
+		pSRB->TotalXferredLen++;
+		pSRB->SGToBeXferLen--;
+	    }
+	}
+    }
+}
+
+static void
+DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = inb(ioport+ScsiFifo);
+    pSRB->TargetStatus = bval;
+    bval++;
+    bval = inb(ioport+ScsiFifo);	/* get message */
+    pSRB->EndMessage = bval;
+
+    *psstatus = SCSI_NOP0;
+    pSRB->SRBState = SRB_COMPLETED;
+    bval = MSG_ACCEPTED_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+	*psstatus = SCSI_NOP0;
+}
+
+static void
+DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport, wval, wval1;
+    PDCB   pDCB;
+    PSRB   psrb;
+
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+
+    bval = inb( ioport+ScsiFifo );
+    if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+    {
+	if(bval == MSG_DISCONNECT)
+	{
+	    pSRB->SRBState = SRB_DISCONNECT;
+	}
+	else if( bval == MSG_SAVE_PTR )
+	    goto  min6;
+	else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
+					    (bval <= MSG_ORDER_QTAG)) )
+	{
+	    pSRB->SRBState |= SRB_MSGIN_MULTI;
+	    pSRB->MsgInBuf[0] = bval;
+	    pSRB->MsgCnt = 1;
+	    pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+	}
+	else if(bval == MSG_REJECT_)
+	{
+	    bval = RESET_ATN_CMD;
+	    outb(bval, ioport+ScsiCmd);
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+		goto  set_async;
+	}
+	else if( bval == MSG_RESTORE_PTR)
+	    goto  min6;
+	else
+	    goto  min6;
+    }
+    else
+    {	/* minx: */
+
+	*pSRB->pMsgPtr = bval;
+	pSRB->MsgCnt++;
+	pSRB->pMsgPtr++;
+	if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
+	    (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
+	{
+	    if( pSRB->MsgCnt == 2)
+	    {
+		pSRB->SRBState = 0;
+		bval = pSRB->MsgInBuf[1];
+		pSRB = pDCB->pGoingSRB;
+		psrb = pDCB->pGoingLast;
+		if( pSRB )
+		{
+		    for( ;; )
+		    {
+			if(pSRB->TagNumber != bval)
+			{
+			    if( pSRB == psrb )
+				goto  mingx0;
+			    pSRB = pSRB->pNextSRB;
+			}
+			else
+			    break;
+		    }
+		    if( pDCB->DCBFlag & ABORT_DEV_ )
+		    {
+			pSRB->SRBState = SRB_ABORT_SENT;
+			EnableMsgOut( pACB, pSRB );
+		    }
+		    if( !(pSRB->SRBState & SRB_DISCONNECT) )
+			goto  mingx0;
+		    pDCB->pActiveSRB = pSRB;
+		    pSRB->SRBState = SRB_DATA_XFER;
+		}
+		else
+		{
+mingx0:
+		    pSRB = pACB->pTmpSRB;
+		    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+		    pDCB->pActiveSRB = pSRB;
+		    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+		    EnableMsgOut2( pACB, pSRB );
+		}
+	    }
+	}
+	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
+	{
+	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
+	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+	    {	/* reject_msg: */
+		pSRB->MsgCnt = 1;
+		pSRB->MsgInBuf[0] = MSG_REJECT_;
+		bval = SET_ATN_CMD;
+		outb(bval, ioport+ScsiCmd);
+	    }
+	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
+	    {
+set_async:
+		pDCB = pSRB->pSRBDCB;
+		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+		pDCB->SyncPeriod = 0;
+		pDCB->SyncOffset = 0;
+		pDCB->CtrlR3 = FAST_CLK;     /* ;non_fast */
+		pDCB->CtrlR4 &= 0x3f;
+		pDCB->CtrlR4 |= EATER_25NS;  /* ; 25ns glitch eater */
+		goto  re_prog;
+	    }
+	    else
+	    {	/* set_sync: */
+
+		pDCB = pSRB->pSRBDCB;
+		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+		pDCB->SyncOffset &= 0x0f0;
+		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+		wval = (USHORT) pSRB->MsgInBuf[3];
+		wval = wval << 2;
+		wval--;
+		wval1 = wval / 25;
+		if( (wval1 * 25) != wval)
+		    wval1++;
+		bval = FAST_CLK+FAST_SCSI;
+		pDCB->CtrlR4 &= 0x3f;
+		if(wval1 >= 8)
+		{
+		    wval1--;
+		    bval = FAST_CLK;	    /* ;fast clock/normal scsi */
+		    pDCB->CtrlR4 |= EATER_25NS;   /* ;25 ns glitch eater */
+		}
+		pDCB->CtrlR3 = bval;
+		pDCB->SyncPeriod = (UCHAR)wval1;
+re_prog:
+		bval = pDCB->SyncPeriod;
+		outb(bval, ioport+Sync_Period);
+		bval = pDCB->SyncOffset;
+		outb(bval, ioport+Sync_Offset);
+		bval = pDCB->CtrlR3;
+		outb(bval, ioport+CtrlReg3);
+		bval = pDCB->CtrlR4;
+		outb(bval, ioport+CtrlReg4);
+		SetXferRate( pACB, pDCB);
+	    }
+	}
+    }
+min6:
+    *psstatus = SCSI_NOP0;
+    bval = MSG_ACCEPTED_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+{
+    PSGL   psgl;
+    UCHAR  bval;
+    USHORT ioport;
+    ULONG  lval;
+
+
+    ioport = pACB->IOPortBase;
+    if( pSRB->SGIndex < pSRB->SGcount )
+    {
+	bval = DMA_IDLE_CMD | ioDir;   /* ;+EN_DMA_INT */
+	outb( bval, ioport+DMA_Cmd);
+	if( !pSRB->SGToBeXferLen )
+	{
+	    psgl = pSRB->pSegmentList;
+#ifndef VERSION_ELF_1_2_13
+	    pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+	    pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	}
+	lval = pSRB->SGToBeXferLen;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_Low);
+	lval = lval >> 8;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_Mid);
+	lval = lval >> 8;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_High);
+
+	lval = pSRB->SGToBeXferLen;
+	outl(lval, ioport+DMA_XferCnt);
+
+	lval = pSRB->SGPhysAddr;
+	outl( lval, ioport+DMA_XferAddr);
+
+	bval = DMA_COMMAND+INFO_XFER_CMD;
+	outb(bval, ioport+ScsiCmd);
+
+	pSRB->SRBState = SRB_DATA_XFER;
+
+	bval = DMA_IDLE_CMD | ioDir;	/* ;+EN_DMA_INT */
+	outb(bval, ioport+DMA_Cmd);
+
+	bval = DMA_START_CMD | ioDir;	/* ;+EN_DMA_INT */
+	outb(bval, ioport+DMA_Cmd);
+    }
+    else    /* xfer pad */
+    {
+	if( pSRB->SGcount )
+	{
+	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+	    pSRB->SRBStatus |= OVER_RUN;
+	}
+	bval = 0;
+	outb(bval,ioport+CtcReg_Low);
+	outb(bval,ioport+CtcReg_Mid);
+	outb(bval,ioport+CtcReg_High);
+
+	pSRB->SRBState |= SRB_XFERPAD;
+	bval = DMA_COMMAND+XFER_PAD_BYTE;
+	outb(bval, ioport+ScsiCmd);
+/*
+	bval = DMA_IDLE_CMD | ioDir;	;+EN_DMA_INT
+	outb(bval, ioport+DMA_Cmd);
+	bval = DMA_START_CMD | ioDir;	;+EN_DMA_INT
+	outb(bval, ioport+DMA_Cmd);
+*/
+    }
+}
+
+
+static void
+DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  ioDir;
+
+    ioDir = WRITE_DIRECTION;
+    DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  ioDir;
+
+    ioDir = READ_DIRECTION;
+    DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    PDCB   pDCB;
+    UCHAR  bval;
+    PUCHAR ptr;
+    USHORT ioport, i,  cnt;
+
+
+    ioport = pACB->IOPortBase;
+    bval = RESET_ATN_CMD;
+    outb(bval, ioport+ScsiCmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+    {
+	cnt = (USHORT) pSRB->ScsiCmdLen;
+	ptr = (PUCHAR) pSRB->CmdBlock;
+	for(i=0; i < cnt; i++)
+	{
+	    outb(*ptr, ioport+ScsiFifo);
+	    ptr++;
+	}
+    }
+    else
+    {
+	bval = REQUEST_SENSE;
+	outb(bval, ioport+ScsiFifo);
+	pDCB = pACB->pActiveDCB;
+	bval = pDCB->IdentifyMsg << 5;
+	outb(bval, ioport+ScsiFifo);
+	bval = 0;
+	outb(bval, ioport+ScsiFifo);
+	outb(bval, ioport+ScsiFifo);
+	bval = sizeof(pSRB->pcmd->sense_buffer);
+	outb(bval, ioport+ScsiFifo);
+	bval = 0;
+	outb(bval, ioport+ScsiFifo);
+    }
+    pSRB->SRBState = SRB_COMMAND;
+    bval = INFO_XFER_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    pSRB->SRBState = SRB_STATUS;
+    bval = INITIATOR_CMD_CMPLTE;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   bval;
+    USHORT  ioport, i, cnt;
+    PUCHAR  ptr;
+    PDCB    pDCB;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    pDCB = pACB->pActiveDCB;
+    if( !(pSRB->SRBState & SRB_MSGOUT) )
+    {
+	cnt = pSRB->MsgCnt;
+	if( cnt )
+	{
+	    ptr = (PUCHAR) pSRB->MsgOutBuf;
+	    for(i=0; i < cnt; i++)
+	    {
+		outb(*ptr, ioport+ScsiFifo);
+		ptr++;
+	    }
+	    pSRB->MsgCnt = 0;
+	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
+		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
+		pSRB->SRBState = SRB_ABORT_SENT;
+	}
+	else
+	{
+	    bval = MSG_ABORT;	/* ??? MSG_NOP */
+	    if( (pSRB->CmdBlock[0] == INQUIRY ) ||
+		(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+		(pSRB->SRBFlag & AUTO_REQSENSE) )
+	    {
+		if( pDCB->SyncMode & SYNC_ENABLE )
+		    goto  mop1;
+	    }
+	    outb(bval, ioport+ScsiFifo);
+	}
+	bval = INFO_XFER_CMD;
+	outb( bval, ioport+ScsiCmd);
+    }
+    else
+    {
+mop1:
+	bval = MSG_EXTENDED;
+	outb(bval, ioport+ScsiFifo);
+	bval = 3;	/*    ;length of extended msg */
+	outb(bval, ioport+ScsiFifo);
+	bval = 1;	/*    ; sync nego */
+	outb(bval, ioport+ScsiFifo);
+	bval = pDCB->NegoPeriod;
+	outb(bval, ioport+ScsiFifo);
+	bval = SYNC_NEGO_OFFSET;
+	outb(bval, ioport+ScsiFifo);
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	bval = INFO_XFER_CMD;
+	outb(bval, ioport+ScsiCmd);
+    }
+}
+
+static void
+DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    if( !(pSRB->SRBState & SRB_MSGIN) )
+    {
+	pSRB->SRBState &= SRB_DISCONNECT;
+	pSRB->SRBState |= SRB_MSGIN;
+    }
+    bval = INFO_XFER_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+
+static void
+SetXferRate( PACB pACB, PDCB pDCB )
+{
+    UCHAR  bval;
+    USHORT cnt, i;
+    PDCB   ptr;
+
+    if( !(pDCB->IdentifyMsg & 0x07) )
+    {
+	if( pACB->scan_devices )
+	{
+	    CurrSyncOffset = pDCB->SyncOffset;
+	}
+	else
+	{
+	    ptr = pACB->pLinkDCB;
+	    cnt = pACB->DeviceCnt;
+	    bval = pDCB->UnitSCSIID;
+	    for(i=0; i<cnt; i++)
+	    {
+		if( ptr->UnitSCSIID == bval )
+		{
+		    ptr->SyncPeriod = pDCB->SyncPeriod;
+		    ptr->SyncOffset = pDCB->SyncOffset;
+		    ptr->CtrlR3 = pDCB->CtrlR3;
+		    ptr->CtrlR4 = pDCB->CtrlR4;
+		    ptr->SyncMode = pDCB->SyncMode;
+		}
+		ptr = ptr->pNextDCB;
+	    }
+	}
+    }
+    return;
+}
+
+
+static void
+DC390_Disconnect( PACB pACB )
+{
+    PDCB   pDCB;
+    PSRB   pSRB, psrb;
+    ULONG  flags;
+    USHORT ioport, i, cnt;
+    UCHAR  bval;
+
+#ifdef DC390_DEBUG0
+    printk("DISC,");
+#endif
+
+    save_flags(flags);
+    cli();
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+    if (!pDCB)
+     {
+#ifdef DC390_DEBUG0
+	printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
+#endif
+	restore_flags(flags); return;
+     }
+    pSRB = pDCB->pActiveSRB;
+    pACB->pActiveDCB = 0;
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = EN_SEL_RESEL;
+    outb(bval, ioport+ScsiCmd);
+    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+    {
+	pSRB->SRBState = 0;
+	DoWaitingSRB( pACB );
+    }
+    else if( pSRB->SRBState & SRB_ABORT_SENT )
+    {
+	pDCB->TagMask = 0;
+	pDCB->DCBFlag = 0;
+	cnt = pDCB->GoingSRBCnt;
+	pDCB->GoingSRBCnt = 0;
+	pSRB = pDCB->pGoingSRB;
+	for( i=0; i < cnt; i++)
+	{
+	    psrb = pSRB->pNextSRB;
+	    pSRB->pNextSRB = pACB->pFreeSRB;
+	    pACB->pFreeSRB = pSRB;
+	    pSRB = psrb;
+	}
+	pDCB->pGoingSRB = 0;
+	DoWaitingSRB( pACB );
+    }
+    else
+    {
+	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+	{	/* Selection time out */
+	    if( !(pACB->scan_devices) )
+	    {
+		pSRB->SRBState = SRB_READY;
+		RewaitSRB( pDCB, pSRB);
+	    }
+	    else
+	    {
+		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+		goto  disc1;
+	    }
+	}
+	else if( pSRB->SRBState & SRB_DISCONNECT )
+	{
+	    DoWaitingSRB( pACB );
+	}
+	else if( pSRB->SRBState & SRB_COMPLETED )
+	{
+disc1:
+	    if(pDCB->MaxCommand > 1)
+	    {
+	       bval = pSRB->TagNumber;
+	       pDCB->TagMask &= (~(1 << bval));   /* free tag mask */
+	    }
+	    pDCB->pActiveSRB = 0;
+	    pSRB->SRBState = SRB_FREE;
+	    SRBdone( pACB, pDCB, pSRB);
+	}
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+DC390_Reselect( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+    PSRB   pSRB;
+    USHORT ioport, wval;
+    UCHAR  bval, bval1;
+
+
+#ifdef DC390_DEBUG0
+    printk("RSEL,");
+#endif
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+    if( pDCB )
+    {	/* Arbitration lost but Reselection win */
+	pSRB = pDCB->pActiveSRB;
+	if( !( pACB->scan_devices ) )
+	{
+	    pSRB->SRBState = SRB_READY;
+	    RewaitSRB( pDCB, pSRB);
+	}
+    }
+    bval = inb(ioport+ScsiFifo);	/* get ID */
+    bval = bval ^ pACB->HostID_Bit;
+    wval = 0;
+    bval1 = 1;
+    for(;;)
+    {
+	if( !(bval & bval1) )
+	{
+	    bval1 = bval1 << 1;
+	    wval++;
+	}
+	else
+	    break;
+    }
+    wval |=  ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8;  /* get LUN */
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
+    {
+	pDCB = pDCB->pNextDCB;
+	if( pDCB == pdcb )
+	    return;
+    }
+    pACB->pActiveDCB = pDCB;
+    if( pDCB->SyncMode & EN_TAG_QUEUING )
+    {
+	pSRB = pACB->pTmpSRB;
+	pDCB->pActiveSRB = pSRB;
+    }
+    else
+    {
+	pSRB = pDCB->pActiveSRB;
+	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+	{
+	    pSRB= pACB->pTmpSRB;
+	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+	    pDCB->pActiveSRB = pSRB;
+	    EnableMsgOut( pACB, pSRB );
+	}
+	else
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+	    {
+		pSRB->SRBState = SRB_ABORT_SENT;
+		EnableMsgOut( pACB, pSRB );
+	    }
+	    else
+		pSRB->SRBState = SRB_DATA_XFER;
+	}
+    }
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = pDCB->UnitSCSIID;
+    outb( bval, ioport+Scsi_Dest_ID);
+    bval = pDCB->SyncPeriod;
+    outb(bval, ioport+Sync_Period);
+    bval = pDCB->SyncOffset;
+    outb( bval, ioport+Sync_Offset);
+    bval = pDCB->CtrlR1;
+    outb(bval, ioport+CtrlReg1);
+    bval = pDCB->CtrlR3;
+    outb(bval, ioport+CtrlReg3);
+    bval = pDCB->CtrlR4;	/* ; Glitch eater */
+    outb(bval, ioport+CtrlReg4);
+    bval = MSG_ACCEPTED_CMD;	/* ;to rls the /ACK signal */
+    outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb;
+    UCHAR  bval, bval1, i, j, status;
+    PSCSICMD pcmd;
+    PSCSI_INQDATA  ptr;
+    USHORT disable_tag;
+    ULONG  flags;
+    PSGL   ptr2;
+    ULONG  swlval;
+
+    pcmd = pSRB->pcmd;
+    status = pSRB->TargetStatus;
+    if(pSRB->SRBFlag & AUTO_REQSENSE)
+    {
+	pSRB->SRBFlag &= ~AUTO_REQSENSE;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+	if(status == SCSI_STAT_CHECKCOND)
+	{
+	    pcmd->result = DID_BAD_TARGET << 16;
+	    goto ckc_e;
+	}
+	if(pSRB->RetryCnt == 0)
+	{
+	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    pSRB->TotalXferredLen = pSRB->Segment1[1];
+	    if( (pSRB->TotalXferredLen) &&
+		(pSRB->TotalXferredLen >= pcmd->underflow) )
+		pcmd->result |= (DID_OK << 16);
+	    else
+		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+				SCSI_STAT_CHECKCOND;
+#ifdef DC390_DEBUG0
+	printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
+		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+#endif
+	    goto ckc_e;
+	}
+	else
+	{
+	    pSRB->RetryCnt--;
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	    {
+		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+				SCSI_STAT_CHECKCOND;
+		goto ckc_e;
+	    }
+	    pcmd->result |= (DRIVER_SENSE << 24);
+	    pSRB->SGcount		 = (UCHAR) pSRB->Segment1[0];
+	    pSRB->ScsiCmdLen		 = (UCHAR) (pSRB->Segment1[0] >> 8);
+	    pSRB->SGIndex = 0;
+	    pSRB->TotalXferredLen = 0;
+	    pSRB->SGToBeXferLen = 0;
+	    if( pcmd->use_sg )
+		pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+	    else if( pcmd->request_buffer )
+	    {
+		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+		pSRB->Segmentx.length = pcmd->request_bufflen;
+	    }
+	    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+		RewaitSRB( pDCB, pSRB );
+	    return;
+	}
+    }
+    if( status )
+    {
+	if( status == SCSI_STAT_CHECKCOND)
+	{
+	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
+	    {
+		bval = pSRB->SGcount;
+		swlval = 0;
+		ptr2 = pSRB->pSegmentList;
+		for( i=pSRB->SGIndex; i < bval; i++)
+		{
+		    swlval += ptr2->length;
+		    ptr2++;
+		}
+#ifdef	DC390_DEBUG0
+		printk("XferredLen=%8x,NotXferLen=%8x,",
+			(UINT) pSRB->TotalXferredLen, (UINT) swlval);
+#endif
+	    }
+	    RequestSense( pACB, pDCB, pSRB );
+	    return;
+	}
+	else if( status == SCSI_STAT_QUEUEFULL )
+	{
+	    bval = (UCHAR) pDCB->GoingSRBCnt;
+	    bval--;
+	    pDCB->MaxCommand = bval;
+	    RewaitSRB( pDCB, pSRB );
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    return;
+	}
+	else if(status == SCSI_STAT_SEL_TIMEOUT)
+	{
+	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result = DID_BAD_TARGET << 16;
+	}
+	else
+	{
+	    pSRB->AdaptStatus = 0;
+	    if( pSRB->RetryCnt )
+	    {
+		pSRB->RetryCnt--;
+		pSRB->TargetStatus = 0;
+		pSRB->SGIndex = 0;
+		pSRB->TotalXferredLen = 0;
+		pSRB->SGToBeXferLen = 0;
+		if( pcmd->use_sg )
+		    pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+		else if( pcmd->request_buffer )
+		{
+		    pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+		    pSRB->Segmentx.length = pcmd->request_bufflen;
+		}
+		if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+		    RewaitSRB( pDCB, pSRB );
+		return;
+	    }
+	    else
+	    {
+		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
+			       (ULONG) status;
+	    }
+	}
+    }
+    else
+    {
+	status = pSRB->AdaptStatus;
+	if(status & H_OVER_UNDER_RUN)
+	{
+	    pSRB->TargetStatus = 0;
+	    pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+	}
+	else if( pSRB->SRBStatus & PARITY_ERROR)
+	{
+	    pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+	}
+	else		       /* No error */
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result |= (DID_OK << 16);
+	}
+    }
+
+ckc_e:
+    if( pACB->scan_devices )
+    {
+	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	{
+	    if(pcmd->result != (DID_OK << 16))
+	    {
+		if( pcmd->result & SCSI_STAT_CHECKCOND )
+		{
+		    goto RTN_OK;
+		}
+		else
+		{
+		    pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+		    pPrevDCB->pNextDCB = pACB->pLinkDCB;
+		    if( (pcmd->target == pACB->max_id) &&
+		       ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
+		    {
+			pACB->scan_devices = 0;
+		    }
+		}
+	    }
+	    else
+	    {
+RTN_OK:
+		pPrevDCB->pNextDCB = pDCB;
+		pDCB->pNextDCB = pACB->pLinkDCB;
+		if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
+		    pACB->scan_devices = END_SCAN;
+	    }
+	}
+	else if( pSRB->CmdBlock[0] == INQUIRY )
+	{
+	    if( (pcmd->target == pACB->max_id) &&
+		(pcmd->lun == pACB->max_lun) )
+	    {
+		pACB->scan_devices = 0;
+	    }
+	    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+	    if( pcmd->use_sg )
+		ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+	    bval1 = ptr->DevType & SCSI_DEVTYPE;
+	    if(bval1 == SCSI_NODEV)
+	    {
+		pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+		pPrevDCB->pNextDCB = pACB->pLinkDCB;
+	    }
+	    else
+	    {
+		pACB->DeviceCnt++;
+		pPrevDCB = pDCB;
+		pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
+		pDCB->DevType = bval1;
+		if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
+		{
+		    if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
+			(ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+			(pDCB->DevMode & TAG_QUEUING_) &&
+			(pDCB->DevMode & EN_DISCONNECT_) )
+		    {
+			disable_tag = 0;
+			for(i=0; i<BADDEVCNT; i++)
+			{
+			    for(j=0; j<28; j++)
+			    {
+				if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
+				    break;
+			    }
+			    if(j == 28)
+			    {
+				disable_tag = 1;
+				break;
+			    }
+			}
+
+			if( !disable_tag )
+			{
+			    pDCB->MaxCommand = pACB->TagMaxNum;
+			    pDCB->SyncMode |= EN_TAG_QUEUING;
+			    pDCB->TagMask = 0;
+			}
+			else
+			{
+			    pDCB->SyncMode |= EN_ATN_STOP;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    save_flags( flags );
+    cli();
+/*  ReleaseSRB( pDCB, pSRB ); */
+
+    if(pSRB == pDCB->pGoingSRB )
+    {
+	pDCB->pGoingSRB = pSRB->pNextSRB;
+    }
+    else
+    {
+	psrb = pDCB->pGoingSRB;
+	while( psrb->pNextSRB != pSRB )
+	    psrb = psrb->pNextSRB;
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pGoingLast )
+	    pDCB->pGoingLast = psrb;
+    }
+    pSRB->pNextSRB = pACB->pFreeSRB;
+    pACB->pFreeSRB = pSRB;
+    pDCB->GoingSRBCnt--;
+
+    DoWaitingSRB( pACB );
+    restore_flags(flags);
+
+/*  Notify cmd done */
+    pcmd->scsi_done( pcmd );
+
+    if( pDCB->QIORBCnt )
+	DoNextCmd( pACB, pDCB );
+    return;
+}
+
+
+static void
+DoingSRB_Done( PACB pACB )
+{
+    PDCB  pDCB, pdcb;
+    PSRB  psrb, psrb2;
+    USHORT  cnt, i;
+    PSCSICMD pcmd;
+
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    do
+    {
+	cnt = pdcb->GoingSRBCnt;
+	psrb = pdcb->pGoingSRB;
+	for( i=0; i<cnt; i++)
+	{
+	    psrb2 = psrb->pNextSRB;
+	    pcmd = psrb->pcmd;
+	    pcmd->result = DID_RESET << 16;
+
+/*	    ReleaseSRB( pDCB, pSRB ); */
+
+	    psrb->pNextSRB = pACB->pFreeSRB;
+	    pACB->pFreeSRB = psrb;
+
+	    pcmd->scsi_done( pcmd );
+	    psrb  = psrb2;
+	}
+	pdcb->GoingSRBCnt = 0;;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+static void
+DC390_ResetSCSIBus( PACB pACB )
+{
+    USHORT ioport;
+    UCHAR  bval;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+    pACB->ACBFlag |= RESET_DEV;
+    ioport = pACB->IOPortBase;
+
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+
+    bval = RST_SCSI_BUS_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+DC390_ScsiRstDetect( PACB pACB )
+{
+    ULONG wlval, flags;
+    USHORT ioport;
+    UCHAR  bval;
+
+#ifdef DC390_DEBUG0
+    printk("RST_DETEC");
+#endif
+    save_flags(flags);
+    sti();
+    wlval = jiffies + HZ;
+    while( jiffies < wlval );	 /* delay 1 sec */
+
+    cli();
+    ioport = pACB->IOPortBase;
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    if( pACB->ACBFlag & RESET_DEV )
+	pACB->ACBFlag |= RESET_DONE;
+    else
+    {
+	pACB->ACBFlag |= RESET_DETECT;
+
+	ResetDevParam( pACB );
+/*	DoingSRB_Done( pACB ); ???? */
+	RecoverSRB( pACB );
+	pACB->pActiveDCB = NULL;
+	pACB->ACBFlag = 0;
+	DoWaitingSRB( pACB );
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    PSCSICMD  pcmd;
+
+    pSRB->SRBFlag |= AUTO_REQSENSE;
+    pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
+    pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+    pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
+    pSRB->Segment1[1] = pSRB->TotalXferredLen;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+
+    pcmd = pSRB->pcmd;
+
+    pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
+    pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+    pSRB->pSegmentList = &pSRB->Segmentx;
+    pSRB->SGcount = 1;
+    pSRB->SGIndex = 0;
+
+    *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+    pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
+    *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+    pSRB->ScsiCmdLen = 6;
+
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGToBeXferLen = 0;
+    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+	RewaitSRB( pDCB, pSRB );
+}
+
+
+static void
+EnableMsgOut2( PACB pACB, PSRB pSRB )
+{
+    USHORT ioport;
+    UCHAR  bval;
+
+    ioport = pACB->IOPortBase;
+    pSRB->MsgCnt = 1;
+    bval = SET_ATN_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+EnableMsgOut( PACB pACB, PSRB pSRB )
+{
+    pSRB->MsgOutBuf[0] = MSG_ABORT;
+    EnableMsgOut2( pACB, pSRB );
+}
+
+
+static void
+DC390_InvalidCmd( PACB pACB )
+{
+   UCHAR bval;
+   USHORT ioport;
+   PSRB   pSRB;
+
+    pSRB = pACB->pActiveDCB->pActiveSRB;
+    if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+    {
+	ioport = pACB->IOPortBase;
+	bval = CLEAR_FIFO_CMD;
+	outb(bval,(ioport+ScsiCmd));
+    }
+}
+
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.36/linux/drivers/scsi/sd.c	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/sd.c	Mon May 12 10:35:42 1997
@@ -1047,7 +1047,7 @@
     spintime = 0;
 
     /* Spin up drives, as required.  Only do this at boot time */
-    if (!MODULE_FLAG){
+    /* Spinup needs to be done for module loads too. */
 	do{
 	    retries = 0;
 	    while(retries < 3)
@@ -1120,7 +1120,6 @@
 	    else
 		printk( "ready\n" );
 	}
-    }  /* !MODULE_FLAG */
 
     retries = 3;
     do {
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.1.36/linux/drivers/scsi/seagate.c	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/seagate.c	Tue May 13 14:41:32 1997
@@ -564,36 +564,6 @@
   return buffer;
 }
 
-int seagate_st0x_proc_info (char *buffer, char **start, off_t offset,
-                            int length, int hostno, int inout)
-{
-  const char *info = seagate_st0x_info (NULL);
-  int len;
-  int pos;
-  int begin;
-
-  if (inout)
-    return (-ENOSYS);
-
-  begin = 0;
-  strcpy (buffer, info);
-  strcat (buffer, "\n");
-
-  pos = len = strlen (buffer);
-
-  if (pos < offset)
-  {
-    len = 0;
-    begin = pos;
-  }
-
-  *start = buffer + (offset - begin);
-  len -= (offset - begin);
-  if (len > length)
-    len = length;
-  return (len);
-}
-
 /*
  * These are our saved pointers for the outstanding command that is
  * waiting for a reconnect
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h
--- v2.1.36/linux/drivers/scsi/seagate.h	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/seagate.h	Tue May 13 14:41:32 1997
@@ -19,7 +19,6 @@
 int seagate_st0x_abort(Scsi_Cmnd *);
 const char *seagate_st0x_info(struct Scsi_Host *);
 int seagate_st0x_reset(Scsi_Cmnd *, unsigned int); 
-int seagate_st0x_proc_info(char *,char **,off_t,int,int,int);
 
 #ifndef NULL
 	#define NULL 0
@@ -28,7 +27,7 @@
 #include <linux/kdev_t.h>
 int seagate_st0x_biosparam(Disk *, kdev_t, int*);
 
-#define SEAGATE_ST0X  {  NULL, NULL, NULL, seagate_st0x_proc_info, \
+#define SEAGATE_ST0X  {  NULL, NULL, NULL, NULL, \
 			 NULL, seagate_st0x_detect, 	\
 			 NULL, 						\
 			 seagate_st0x_info, seagate_st0x_command,  	\
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.1.36/linux/drivers/scsi/tmscsim.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/tmscsim.c	Mon May 12 10:35:42 1997
@@ -0,0 +1,1928 @@
+/***********************************************************************
+ *	FILE NAME : TMSCSIM.C					       *
+ *	     BY   : C.L. Huang,  ching@tekram.com.tw		       *
+ *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
+ *		     Bus Master Host Adapter			       *
+ * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.		       *
+ ***********************************************************************/
+/*	Minor enhancements and bugfixes by				*
+ *	Kurt Garloff <K.Garloff@ping.de>				*
+ ***********************************************************************/
+/*	HISTORY:							*
+ *									*
+ *	REV#	DATE	NAME	DESCRIPTION				*
+ *	1.00  04/24/96	CLH	First release				*
+ *	1.01  06/12/96	CLH	Fixed bug of Media Change for Removable *
+ *				Device, scan all LUN. Support Pre2.0.10 *
+ *	1.02  06/18/96	CLH	Fixed bug of Command timeout ...	*
+ *	1.03  09/25/96	KG	Added tmscsim_proc_info()		*
+ *	1.04  10/11/96	CLH	Updating for support KV 2.0.x		*
+ *	1.05  10/18/96	KG	Fixed bug in DC390_abort(null ptr deref)*
+ *	1.06  10/25/96	KG	Fixed module support			*
+ *	1.07  11/09/96	KG	Fixed tmscsim_proc_info()		*
+ *	1.08  11/18/96	KG	Fixed null ptr in DC390_Disconnect()	*
+ *	1.09  11/30/96	KG	Added register the allocated IO space	*
+ *	1.10  12/05/96	CLH	Modified tmscsim_proc_info(), and reset *
+ *				pending interrupt in DC390_detect()	*
+ ***********************************************************************/
+
+
+#define DC390_DEBUG
+
+#define SCSI_MALLOC
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
+#include "../block/blk.h"
+#else
+#include <linux/blk.h>
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "tmscsim.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+
+#include "dc390.h"
+
+#define PCI_DEVICE_ID_AMD53C974 	PCI_DEVICE_ID_AMD_SCSI
+
+
+#ifndef  VERSION_ELF_1_2_13
+struct proc_dir_entry	proc_scsi_tmscsim ={
+       PROC_SCSI_DC390T, 7 ,"tmscsim",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+       };
+#endif
+
+static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void SetXferRate( PACB pACB, PDCB pDCB );
+static void DC390_Disconnect( PACB pACB );
+static void DC390_Reselect( PACB pACB );
+static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DoingSRB_Done( PACB pACB );
+static void DC390_ScsiRstDetect( PACB pACB );
+static void DC390_ResetSCSIBus( PACB pACB );
+static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void EnableMsgOut( PACB pACB, PSRB pSRB );
+static void DC390_InvalidCmd( PACB pACB );
+
+int    DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
+void   DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *host);
+static int DC390_shutdown (struct Scsi_Host *host);
+#endif
+
+
+static PSHT	pSHT_start = NULL;
+static PSH	pSH_start = NULL;
+static PSH	pSH_current = NULL;
+static PACB	pACB_start= NULL;
+static PACB	pACB_current = NULL;
+static PDCB	pPrevDCB = NULL;
+static USHORT	adapterCnt = 0;
+static USHORT	InitialTime = 0;
+static USHORT	CurrSyncOffset = 0;
+static ULONG	mech1addr;
+static UCHAR	mech2bus, mech2Agent, mech2CfgSPenR;
+
+static PVOID DC390_phase0[]={
+       DC390_DataOut_0,
+       DC390_DataIn_0,
+       DC390_Command_0,
+       DC390_Status_0,
+       DC390_Nop_0,
+       DC390_Nop_0,
+       DC390_MsgOut_0,
+       DC390_MsgIn_0,
+       DC390_Nop_1
+       };
+
+static PVOID DC390_phase1[]={
+       DC390_DataOutPhase,
+       DC390_DataInPhase,
+       DC390_CommandPhase,
+       DC390_StatusPhase,
+       DC390_Nop_0,
+       DC390_Nop_0,
+       DC390_MsgOutPhase,
+       DC390_MsgInPhase,
+       DC390_Nop_1,
+       };
+
+UCHAR  eepromBuf[MAX_ADAPTER_NUM][128];
+
+
+UCHAR  clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+UCHAR  baddevname1[2][28] ={
+       "SEAGATE ST3390N         9546",
+       "HP      C3323-300       4269"};
+
+#define BADDEVCNT	2
+
+
+/***********************************************************************
+ *
+ *
+ *
+ **********************************************************************/
+static void
+QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+    ULONG  flags;
+    PSCSICMD  pcmd;
+
+    save_flags(flags);
+    cli();
+
+    if( !pDCB->QIORBCnt )
+    {
+	pDCB->pQIORBhead = cmd;
+	pDCB->pQIORBtail = cmd;
+	pDCB->QIORBCnt++;
+	cmd->next = NULL;
+    }
+    else
+    {
+	pcmd = pDCB->pQIORBtail;
+	pcmd->next = cmd;
+	pDCB->pQIORBtail = cmd;
+	pDCB->QIORBCnt++;
+	cmd->next = NULL;
+    }
+
+    restore_flags(flags);
+}
+
+
+static PSCSICMD
+Getcmd( PDCB pDCB )
+{
+    ULONG  flags;
+    PSCSICMD  pcmd;
+
+    save_flags(flags);
+    cli();
+
+    pcmd = pDCB->pQIORBhead;
+    pDCB->pQIORBhead = pcmd->next;
+    pcmd->next = NULL;
+    pDCB->QIORBCnt--;
+
+    restore_flags(flags);
+    return( pcmd );
+}
+
+
+static PSRB
+GetSRB( PACB pACB )
+{
+    ULONG  flags;
+    PSRB   pSRB;
+
+    save_flags(flags);
+    cli();
+
+    pSRB = pACB->pFreeSRB;
+    if( pSRB )
+    {
+	pACB->pFreeSRB = pSRB->pNextSRB;
+	pSRB->pNextSRB = NULL;
+    }
+    restore_flags(flags);
+    return( pSRB );
+}
+
+
+static void
+RewaitSRB0( PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb1;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+
+    if( (psrb1 = pDCB->pWaitingSRB) )
+    {
+	pSRB->pNextSRB = psrb1;
+	pDCB->pWaitingSRB = pSRB;
+    }
+    else
+    {
+	pSRB->pNextSRB = NULL;
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+    restore_flags(flags);
+}
+
+
+static void
+RewaitSRB( PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb1;
+    ULONG  flags;
+    UCHAR  bval;
+
+    save_flags(flags);
+    cli();
+    pDCB->GoingSRBCnt--;
+    psrb1 = pDCB->pGoingSRB;
+    if( pSRB == psrb1 )
+    {
+	pDCB->pGoingSRB = psrb1->pNextSRB;
+    }
+    else
+    {
+	while( pSRB != psrb1->pNextSRB )
+	    psrb1 = psrb1->pNextSRB;
+	psrb1->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pGoingLast )
+	    pDCB->pGoingLast = psrb1;
+    }
+    if( (psrb1 = pDCB->pWaitingSRB) )
+    {
+	pSRB->pNextSRB = psrb1;
+	pDCB->pWaitingSRB = pSRB;
+    }
+    else
+    {
+	pSRB->pNextSRB = NULL;
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+
+    bval = pSRB->TagNumber;
+    pDCB->TagMask &= (~(1 << bval));	  /* Free TAG number */
+    restore_flags(flags);
+}
+
+
+static void
+DoWaitingSRB( PACB pACB )
+{
+    ULONG  flags;
+    PDCB   ptr, ptr1;
+    PSRB   pSRB;
+
+    save_flags(flags);
+    cli();
+
+    if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
+    {
+	ptr = pACB->pDCBRunRobin;
+	if( !ptr )
+	{
+	    ptr = pACB->pLinkDCB;
+	    pACB->pDCBRunRobin = ptr;
+	}
+	ptr1 = ptr;
+	for( ;ptr1; )
+	{
+	    pACB->pDCBRunRobin = ptr1->pNextDCB;
+	    if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
+		!( pSRB = ptr1->pWaitingSRB ) )
+	    {
+		if(pACB->pDCBRunRobin == ptr)
+		    break;
+		ptr1 = ptr1->pNextDCB;
+	    }
+	    else
+	    {
+		if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+		{
+		    ptr1->GoingSRBCnt++;
+		    if( ptr1->pWaitLast == pSRB )
+		    {
+			ptr1->pWaitingSRB = NULL;
+			ptr1->pWaitLast = NULL;
+		    }
+		    else
+		    {
+			ptr1->pWaitingSRB = pSRB->pNextSRB;
+		    }
+		    pSRB->pNextSRB = NULL;
+
+		    if( ptr1->pGoingSRB )
+			ptr1->pGoingLast->pNextSRB = pSRB;
+		    else
+			ptr1->pGoingSRB = pSRB;
+		    ptr1->pGoingLast = pSRB;
+		}
+		break;
+	    }
+	}
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+SRBwaiting( PDCB pDCB, PSRB pSRB)
+{
+    if( pDCB->pWaitingSRB )
+    {
+	pDCB->pWaitLast->pNextSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+	pSRB->pNextSRB = NULL;
+    }
+    else
+    {
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+}
+
+
+static void
+SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+{
+    ULONG  flags;
+    PDCB   pDCB;
+
+    save_flags(flags);
+    cli();
+
+    pDCB = pSRB->pSRBDCB;
+    if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
+	(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
+    {
+	SRBwaiting(pDCB, pSRB);
+	goto SND_EXIT;
+    }
+
+    if( pDCB->pWaitingSRB )
+    {
+	SRBwaiting(pDCB, pSRB);
+/*	pSRB = GetWaitingSRB(pDCB); */
+	pSRB = pDCB->pWaitingSRB;
+	pDCB->pWaitingSRB = pSRB->pNextSRB;
+	pSRB->pNextSRB = NULL;
+    }
+
+    if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+    {
+	pDCB->GoingSRBCnt++;
+	if( pDCB->pGoingSRB )
+	{
+	    pDCB->pGoingLast->pNextSRB = pSRB;
+	    pDCB->pGoingLast = pSRB;
+	}
+	else
+	{
+	    pDCB->pGoingSRB = pSRB;
+	    pDCB->pGoingLast = pSRB;
+	}
+    }
+    else
+	RewaitSRB0( pDCB, pSRB );
+
+SND_EXIT:
+    restore_flags(flags);
+    return;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
+ *					       void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	    a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ ***********************************************************************/
+
+int
+DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+    USHORT ioport, i;
+    Scsi_Cmnd *pcmd;
+    struct Scsi_Host *psh;
+    PACB   pACB;
+    PDCB   pDCB;
+    PSRB   pSRB;
+    ULONG  flags;
+    PUCHAR ptr,ptr1;
+
+    psh = cmd->host;
+    pACB = (PACB ) psh->hostdata;
+    ioport = pACB->IOPortBase;
+
+#ifdef DC390_DEBUG0
+/*  if(pACB->scan_devices) */
+	printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
+#endif
+
+    if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
+    {
+	pACB->scan_devices = 0;
+	pPrevDCB->pNextDCB = pACB->pLinkDCB;
+    }
+    else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
+    {
+	pACB->scan_devices = 0;
+	pPrevDCB->pNextDCB = pACB->pLinkDCB;
+    }
+
+    if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+    {
+/*	printk("DC390: Ignore target %d lun %d\n",
+		cmd->target, cmd->lun); */
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	return( 0 );
+    }
+
+    if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    {
+	if( pACB->DeviceCnt < MAX_DEVICES )
+	{
+	    pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+	    pDCB = pACB->pDCB_free;
+#ifdef DC390_DEBUG0
+	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+	    DC390_initDCB( pACB, pDCB, cmd );
+	}
+	else	/* ???? */
+	{
+/*	    printk("DC390: Ignore target %d lun %d\n",
+		    cmd->target, cmd->lun); */
+	    cmd->result = (DID_BAD_TARGET << 16);
+	    done(cmd);
+	    return(0);
+	}
+    }
+    else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    {
+/*	printk("DC390: Ignore target %d lun %d\n",
+		cmd->target, cmd->lun); */
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	return(0);
+    }
+    else
+    {
+	pDCB = pACB->pLinkDCB;
+	while( (pDCB->UnitSCSIID != cmd->target) ||
+	       (pDCB->UnitSCSILUN != cmd->lun) )
+	{
+	    pDCB = pDCB->pNextDCB;
+	}
+#ifdef DC390_DEBUG0
+	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+    }
+
+    cmd->scsi_done = done;
+    cmd->result = 0;
+
+    save_flags(flags);
+    cli();
+
+    if( pDCB->QIORBCnt )
+    {
+	QLinkcmd( cmd, pDCB );
+	pcmd = Getcmd( pDCB );
+    }
+    else
+	pcmd = cmd;
+
+    pSRB = GetSRB( pACB );
+
+    if( !pSRB )
+    {
+	QLinkcmd( pcmd, pDCB );
+	restore_flags(flags);
+	return(0);
+    }
+
+/*  BuildSRB(pSRB); */
+
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    ptr = (PUCHAR) pSRB->CmdBlock;
+    ptr1 = (PUCHAR) pcmd->cmnd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    for(i=0; i< pcmd->cmd_len; i++)
+    {
+	*ptr = *ptr1;
+	ptr++;
+	ptr1++;
+    }
+    if( pcmd->use_sg )
+    {
+	pSRB->SGcount = (UCHAR) pcmd->use_sg;
+	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+	pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+	pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+	pSRB->RetryCnt = 1;
+    else
+	pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGPhysAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+    SendSRB( pcmd, pACB, pSRB );
+
+    restore_flags(flags);
+    return(0);
+}
+
+
+static void
+DoNextCmd( PACB pACB, PDCB pDCB )
+{
+    Scsi_Cmnd *pcmd;
+    PSRB   pSRB;
+    ULONG  flags;
+    PUCHAR ptr,ptr1;
+    USHORT i;
+
+
+    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+	return;
+    save_flags(flags);
+    cli();
+
+    pcmd = Getcmd( pDCB );
+    pSRB = GetSRB( pACB );
+    if( !pSRB )
+    {
+	QLinkcmd( pcmd, pDCB );
+	restore_flags(flags);
+	return;
+    }
+
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    ptr = (PUCHAR) pSRB->CmdBlock;
+    ptr1 = (PUCHAR) pcmd->cmnd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    for(i=0; i< pcmd->cmd_len; i++)
+    {
+	*ptr = *ptr1;
+	ptr++;
+	ptr1++;
+    }
+    if( pcmd->use_sg )
+    {
+	pSRB->SGcount = (UCHAR) pcmd->use_sg;
+	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+	pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+	pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+	pSRB->RetryCnt = 1;
+    else
+	pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGPhysAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+    SendSRB( pcmd, pACB, pSRB );
+
+    restore_flags(flags);
+    return;
+}
+
+
+/***********************************************************************
+ * Function:
+ *   DC390_bios_param
+ *
+ * Description:
+ *   Return the disk geometry for the given SCSI device.
+ ***********************************************************************/
+#ifdef	VERSION_ELF_1_2_13
+int DC390_bios_param(Disk *disk, int devno, int geom[])
+#else
+int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+#endif
+{
+    int heads, sectors, cylinders;
+    PACB pACB;
+
+    pACB = (PACB) disk->device->host->hostdata;
+    heads = 64;
+    sectors = 32;
+    cylinders = disk->capacity / (heads * sectors);
+
+    if ( cylinders > 1024)
+    {
+      heads = 255;
+      sectors = 63;
+      cylinders = disk->capacity / (255 * 63);
+    }
+
+    geom[0] = heads;
+    geom[1] = sectors;
+    geom[2] = cylinders;
+
+    return (0);
+}
+
+
+/***********************************************************************
+ * Function : int DC390_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command
+ *
+ * Inputs : cmd - command to abort
+ *
+ * Returns : 0 on success, -1 on failure.
+ ***********************************************************************/
+
+int
+DC390_abort (Scsi_Cmnd *cmd)
+{
+    ULONG flags;
+    PACB  pACB;
+    PDCB  pDCB, pdcb;
+    PSRB  pSRB, psrb;
+    USHORT count, i;
+    PSCSICMD  pcmd, pcmd1;
+    int   status;
+
+
+#ifdef DC390_DEBUG0
+    printk("DC390 : Abort Cmd.");
+#endif
+
+    save_flags(flags);
+    cli();
+
+    pACB = (PACB) cmd->host->hostdata;
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    while( (pDCB->UnitSCSIID != cmd->target) ||
+	   (pDCB->UnitSCSILUN != cmd->lun) )
+    {
+	pDCB = pDCB->pNextDCB;
+	if( pDCB == pdcb )
+	    goto  NOT_RUN;
+    }
+
+    if( pDCB->QIORBCnt )
+    {
+	pcmd = pDCB->pQIORBhead;
+	if( pcmd == cmd )
+	{
+	    pDCB->pQIORBhead = pcmd->next;
+	    pcmd->next = NULL;
+	    pDCB->QIORBCnt--;
+	    status = SCSI_ABORT_SUCCESS;
+	    goto  ABO_X;
+	}
+	for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
+	{
+	    if( pcmd->next == cmd )
+	    {
+		pcmd1 = pcmd->next;
+		pcmd->next = pcmd1->next;
+		pcmd1->next = NULL;
+		pDCB->QIORBCnt--;
+		status = SCSI_ABORT_SUCCESS;
+		goto  ABO_X;
+	    }
+	    else
+	    {
+		pcmd = pcmd->next;
+	    }
+	}
+    }
+
+    pSRB = pDCB->pWaitingSRB;
+    if( !pSRB )
+	goto  ON_GOING;
+    if( pSRB->pcmd == cmd )
+    {
+	pDCB->pWaitingSRB = pSRB->pNextSRB;
+	goto  IN_WAIT;
+    }
+    else
+    {
+	psrb = pSRB;
+	if( !(psrb->pNextSRB) )
+	    goto ON_GOING;
+	while( psrb->pNextSRB->pcmd != cmd )
+	{
+	    psrb = psrb->pNextSRB;
+	    if( !(psrb->pNextSRB) )
+		goto ON_GOING;
+	}
+	pSRB = psrb->pNextSRB;
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pWaitLast )
+	    pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */
+IN_WAIT:
+	pSRB->pNextSRB = pACB->pFreeSRB;
+	pACB->pFreeSRB = pSRB;
+	cmd->next = NULL;
+	status = SCSI_ABORT_SUCCESS;
+	goto  ABO_X;
+    }
+
+ON_GOING:
+    pSRB = pDCB->pGoingSRB;
+    for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
+    {
+	if( pSRB->pcmd != cmd )
+	    pSRB = pSRB->pNextSRB;
+	else
+	{
+	    if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
+	    {
+		status = SCSI_ABORT_BUSY;
+		goto  ABO_X;
+	    }
+	    else
+	    {
+		status = SCSI_ABORT_SNOOZE;
+		goto  ABO_X;
+	    }
+	}
+    }
+
+NOT_RUN:
+    status = SCSI_ABORT_NOT_RUNNING;
+
+ABO_X:
+    cmd->result = DID_ABORT << 16;
+    cmd->scsi_done(cmd);
+    restore_flags(flags);
+    return( status );
+}
+
+
+static void
+ResetDevParam( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+
+    pDCB = pACB->pLinkDCB;
+    if( pDCB == NULL )
+	return;
+    pdcb = pDCB;
+    do
+    {
+	pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+	pDCB->SyncPeriod = 0;
+	pDCB->SyncOffset = 0;
+	pDCB->CtrlR3 = FAST_CLK;
+	pDCB->CtrlR4 &= NEGATE_REQACKDATA;
+	pDCB->CtrlR4 |= EATER_25NS;
+	pDCB = pDCB->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+static void
+RecoverSRB( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+    PSRB   psrb, psrb2;
+    USHORT cnt, i;
+
+    pDCB = pACB->pLinkDCB;
+    if( pDCB == NULL )
+	return;
+    pdcb = pDCB;
+    do
+    {
+	cnt = pdcb->GoingSRBCnt;
+	psrb = pdcb->pGoingSRB;
+	for (i=0; i<cnt; i++)
+	{
+	    psrb2 = psrb;
+	    psrb = psrb->pNextSRB;
+/*	    RewaitSRB( pDCB, psrb ); */
+	    if( pdcb->pWaitingSRB )
+	    {
+		psrb2->pNextSRB = pdcb->pWaitingSRB;
+		pdcb->pWaitingSRB = psrb2;
+	    }
+	    else
+	    {
+		pdcb->pWaitingSRB = psrb2;
+		pdcb->pWaitLast = psrb2;
+		psrb2->pNextSRB = NULL;
+	    }
+	}
+	pdcb->GoingSRBCnt = 0;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+/***********************************************************************
+ * Function : int DC390_reset (Scsi_Cmnd *cmd, ...)
+ *
+ * Purpose : perform a hard reset on the SCSI bus
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ ***********************************************************************/
+
+#ifdef	VERSION_2_0_0
+int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+#else
+int DC390_reset (Scsi_Cmnd *cmd)
+#endif
+{
+    USHORT   ioport;
+    unsigned long flags;
+    PACB  pACB;
+    UCHAR    bval;
+    USHORT  i;
+
+
+#ifdef DC390_DEBUG1
+    printk("DC390: RESET,");
+#endif
+
+    pACB = (PACB ) cmd->host->hostdata;
+    ioport = pACB->IOPortBase;
+    save_flags(flags);
+    cli();
+    bval = inb(ioport+CtrlReg1);
+    bval |= DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
+    DC390_ResetSCSIBus( pACB );
+    for( i=0; i<500; i++ )
+	udelay(1000);
+    bval = inb(ioport+CtrlReg1);
+    bval &= ~DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    ResetDevParam( pACB );
+    DoingSRB_Done( pACB );
+    pACB->pActiveDCB = NULL;
+
+    pACB->ACBFlag = 0;
+    DoWaitingSRB( pACB );
+
+    restore_flags(flags);
+#ifdef DC390_DEBUG1
+    printk("DC390: RESET1,");
+#endif
+    return( SCSI_RESET_SUCCESS );
+}
+
+
+#include "scsiiom.c"
+
+
+/***********************************************************************
+ * Function : static void DC390_initDCB
+ *
+ * Purpose :  initialize the internal structures for a given DCB
+ *
+ * Inputs : cmd - pointer to this scsi cmd request block structure
+ *
+ ***********************************************************************/
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+{
+    PEEprom	prom;
+    UCHAR	bval;
+    USHORT	index;
+
+    if( pACB->DeviceCnt == 0 )
+    {
+	pACB->pLinkDCB = pDCB;
+	pACB->pDCBRunRobin = pDCB;
+	pDCB->pNextDCB = pDCB;
+	pPrevDCB = pDCB;
+    }
+    else
+	pPrevDCB->pNextDCB = pDCB;
+
+    pDCB->pDCBACB = pACB;
+    pDCB->QIORBCnt = 0;
+    pDCB->UnitSCSIID = cmd->target;
+    pDCB->UnitSCSILUN = cmd->lun;
+    pDCB->pWaitingSRB = NULL;
+    pDCB->pGoingSRB = NULL;
+    pDCB->GoingSRBCnt = 0;
+    pDCB->pActiveSRB = NULL;
+    pDCB->TagMask = 0;
+    pDCB->MaxCommand = 1;
+    pDCB->AdaptIndex = pACB->AdapterIndex;
+    index = pACB->AdapterIndex;
+    pDCB->DCBFlag = 0;
+
+    prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+    pDCB->DevMode = prom->EE_MODE1;
+    pDCB->AdpMode = eepromBuf[index][EE_MODE2];
+
+    if( pDCB->DevMode & EN_DISCONNECT_ )
+	bval = 0xC0;
+    else
+	bval = 0x80;
+    bval |= cmd->lun;
+    pDCB->IdentifyMsg = bval;
+
+    pDCB->SyncMode = 0;
+    if( pDCB->DevMode & SYNC_NEGO_ )
+    {
+	if( !(cmd->lun) || CurrSyncOffset )
+	    pDCB->SyncMode = SYNC_ENABLE;
+    }
+
+    pDCB->SyncPeriod = 0;
+    pDCB->SyncOffset = 0;
+    pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
+
+    pDCB->CtrlR1 = pACB->AdaptSCSIID;
+    if( pDCB->DevMode & PARITY_CHK_ )
+	pDCB->CtrlR1 |= PARITY_ERR_REPO;
+
+    pDCB->CtrlR3 = FAST_CLK;
+
+    pDCB->CtrlR4 = EATER_25NS;
+    if( pDCB->AdpMode & ACTIVE_NEGATION)
+	pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initSRB
+ *
+ * Purpose :  initialize the internal structures for a given SRB
+ *
+ * Inputs : psrb - pointer to this scsi request block structure
+ *
+ ***********************************************************************/
+void DC390_initSRB( PSRB psrb )
+{
+#ifndef VERSION_ELF_1_2_13
+#ifdef DC390_DEBUG0
+   printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
+#endif
+	psrb->PhysSRB = virt_to_bus( psrb );
+#else
+	psrb->PhysSRB = (ULONG) psrb;
+#endif
+}
+
+
+void DC390_linkSRB( PACB pACB )
+{
+    USHORT  count, i;
+    PSRB    psrb;
+
+    count = pACB->SRBCount;
+
+    for( i=0; i< count; i++)
+    {
+	if( i != count - 1)
+	    pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
+	else
+	    pACB->SRB_array[i].pNextSRB = NULL;
+	psrb = (PSRB) &pACB->SRB_array[i];
+	DC390_initSRB( psrb );
+    }
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initACB
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+    PACB    pACB;
+    USHORT  i;
+
+    psh->can_queue = MAX_CMD_QUEUE;
+    psh->cmd_per_lun = MAX_CMD_PER_LUN;
+    psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+    psh->io_port = io_port;
+    psh->n_io_port = 0x80;
+    psh->irq = Irq;
+
+    pACB = (PACB) psh->hostdata;
+
+#ifndef VERSION_ELF_1_2_13
+    psh->max_id = 8;
+#ifdef	CONFIG_SCSI_MULTI_LUN
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	psh->max_lun = 8;
+    else
+#endif
+	psh->max_lun = 1;
+#endif
+
+    pACB->max_id = 7;
+    if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
+	pACB->max_id--;
+#ifdef	CONFIG_SCSI_MULTI_LUN
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	pACB->max_lun = 7;
+    else
+#endif
+	pACB->max_lun = 0;
+
+    pACB->pScsiHost = psh;
+    pACB->IOPortBase = (USHORT) io_port;
+    pACB->pLinkDCB = NULL;
+    pACB->pDCBRunRobin = NULL;
+    pACB->pActiveDCB = NULL;
+    pACB->pFreeSRB = pACB->SRB_array;
+    pACB->SRBCount = MAX_SRB_CNT;
+    pACB->AdapterIndex = index;
+    pACB->status = 0;
+    pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
+    pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
+    pACB->AdaptSCSILUN = 0;
+    pACB->DeviceCnt = 0;
+    pACB->IRQLevel = Irq;
+    pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+    pACB->ACBFlag = 0;
+    pACB->scan_devices = 1;
+    pACB->Gmode2 = eepromBuf[index][EE_MODE2];
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	pACB->LUNchk = 1;
+    pACB->pDCB_free = &pACB->DCB_array[0];
+    DC390_linkSRB( pACB );
+    pACB->pTmpSRB = &pACB->TmpSRB;
+    DC390_initSRB( pACB->pTmpSRB );
+    for(i=0; i<MAX_SCSI_ID; i++)
+	pACB->DCBmap[i] = 0;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_initAdapter
+ *
+ * Purpose :  initialize the SCSI chip ctrl registers
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+    USHORT ioport;
+    UCHAR  bval;
+    PACB   pACB, pacb;
+    USHORT used_irq = 0;
+
+    pacb = pACB_start;
+    if( pacb != NULL )
+    {
+	for ( ; (pacb != (PACB) -1) ; )
+	{
+	    if( pacb->IRQLevel == Irq )
+	    {
+		used_irq = 1;
+		break;
+	    }
+	    else
+		pacb = pacb->pNextACB;
+	}
+    }
+
+    if( !used_irq )
+    {
+#ifdef	VERSION_ELF_1_2_13
+	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
+#else
+	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+#endif
+	{
+	    printk("DC390: register IRQ error!\n");
+	    return( -1 );
+	}
+    }
+
+    request_region(io_port,psh->n_io_port,"tmscsim");
+
+    ioport = (USHORT) io_port;
+
+    pACB = (PACB) psh->hostdata;
+    bval = SEL_TIMEOUT; 		/* 250ms selection timeout */
+    outb(bval,ioport+Scsi_TimeOut);
+
+    bval = CLK_FREQ_40MHZ;		/* Conversion factor = 0 , 40MHz clock */
+    outb(bval,ioport+Clk_Factor);
+
+    bval = NOP_CMD;			/* NOP cmd - clear command register */
+    outb(bval,ioport+ScsiCmd);
+
+    bval = EN_FEATURE+EN_SCSI2_CMD;	/* Enable Feature and SCSI-2 */
+    outb(bval,ioport+CtrlReg2);
+
+    bval = FAST_CLK;			/* fast clock */
+    outb(bval,ioport+CtrlReg3);
+
+    bval = EATER_25NS;
+    if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
+	 bval |= NEGATE_REQACKDATA;
+    outb(bval,ioport+CtrlReg4);
+
+    bval = DIS_INT_ON_SCSI_RST; 	/* Disable SCSI bus reset interrupt */
+    outb(bval,ioport+CtrlReg1);
+
+    return(0);
+}
+
+
+void
+DC390_EnableCfg( USHORT mechnum, UCHAR regval )
+{
+    ULONG wlval;
+
+    if(mechnum == 2)
+    {
+	outb(mech2bus, PCI_CFG2_FORWARD_REG);
+	outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
+    }
+    else
+    {
+	regval &= 0xFC;
+	wlval = mech1addr;
+	wlval |= (((ULONG)regval) & 0xff);
+	outl(wlval, PCI_CFG1_ADDRESS_REG);
+    }
+}
+
+
+void
+DC390_DisableCfg( USHORT mechnum )
+{
+
+    if(mechnum == 2)
+	outb(0, PCI_CFG2_ENABLE_REG);
+    else
+	outl(0, PCI_CFG1_ADDRESS_REG);
+}
+
+
+UCHAR
+DC390_inByte( USHORT mechnum, UCHAR regval )
+{
+    UCHAR bval;
+    ULONG wval;
+    ULONG flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg( mechnum, regval );
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= ((USHORT) regval) & 0xff;
+	bval = inb(wval);
+    }
+    else
+    {
+	regval &= 3;
+	bval = inb(PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(bval);
+}
+
+
+USHORT
+DC390_inWord( USHORT mechnum, UCHAR regval )
+{
+    USHORT wval;
+    ULONG flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	wval = inw(wval);
+    }
+    else
+    {
+	regval &= 3;
+	wval = inw(PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(wval);
+}
+
+
+ULONG
+DC390_inDword(USHORT mechnum, UCHAR regval )
+{
+    ULONG wlval;
+    ULONG flags;
+    USHORT wval;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	wlval = inl(wval);
+    }
+    else
+    {
+	wlval = inl(PCI_CFG1_DATA_REG);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(wlval);
+}
+
+
+void
+DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
+{
+
+    USHORT wval;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	outb(bval, wval);
+    }
+    else
+    {
+	regval &= 3;
+	outb(bval, PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+}
+
+
+void
+DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
+{
+
+    UCHAR bval;
+
+    bval = 0;
+    if(mode == ENABLE_CE)
+	*regval = 0xc0;
+    else
+	*regval = 0x80;
+    DC390_OutB(mechnum,*regval,bval);
+    if(mode == DISABLE_CE)
+	DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+}
+
+
+void
+DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
+{
+    UCHAR bval;
+
+    bval = 0;
+    if(Carry)
+    {
+	bval = 0x40;
+	*regval = 0x80;
+	DC390_OutB(mechnum,*regval,bval);
+    }
+    udelay(160);
+    bval |= 0x80;
+    DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+    bval = 0;
+    DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+}
+
+
+UCHAR
+DC390_EEpromInDO( USHORT mechnum )
+{
+    UCHAR bval,regval;
+
+    regval = 0x80;
+    bval = 0x80;
+    DC390_OutB(mechnum,regval,bval);
+    udelay(160);
+    bval = 0x40;
+    DC390_OutB(mechnum,regval,bval);
+    udelay(160);
+    regval = 0x0;
+    bval = DC390_inByte(mechnum,regval);
+    if(bval == 0x22)
+	return(1);
+    else
+	return(0);
+}
+
+
+USHORT
+EEpromGetData1( USHORT mechnum )
+{
+    UCHAR i;
+    UCHAR carryFlag;
+    USHORT wval;
+
+    wval = 0;
+    for(i=0; i<16; i++)
+    {
+	wval <<= 1;
+	carryFlag = DC390_EEpromInDO(mechnum);
+	wval |= carryFlag;
+    }
+    return(wval);
+}
+
+
+void
+DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
+{
+    UCHAR i,j;
+    USHORT carryFlag;
+
+    carryFlag = 1;
+    j = 0x80;
+    for(i=0; i<9; i++)
+    {
+	DC390_EEpromOutDI(mechnum,regval,carryFlag);
+	carryFlag = (EEpromCmd & j) ? 1 : 0;
+	j >>= 1;
+    }
+}
+
+
+void
+DC390_ReadEEprom( USHORT mechnum, USHORT index )
+{
+    UCHAR   regval,cmd;
+    PUSHORT ptr;
+    USHORT  i;
+
+    ptr = (PUSHORT) &eepromBuf[index][0];
+    cmd = EEPROM_READ;
+    for(i=0; i<0x40; i++)
+    {
+	DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
+	DC390_Prepare(mechnum, &regval, cmd);
+	*ptr = EEpromGetData1(mechnum);
+	ptr++;
+	cmd++;
+	DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+    }
+}
+
+
+USHORT
+DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
+{
+    USHORT wval, rc, *ptr;
+    UCHAR  i;
+
+    DC390_ReadEEprom( MechNum, index );
+    wval = 0;
+    ptr = (PUSHORT) &eepromBuf[index][0];
+    for(i=0; i<128 ;i+=2, ptr++)
+	wval += *ptr;
+    if( wval == 0x1234 )
+	rc = 0;
+    else
+	rc = -1;
+    return( rc );
+}
+
+
+USHORT
+DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
+{
+    USHORT devnum;
+
+    devnum = BusDevFunNum;
+
+    if(Mechnum == 2)
+    {
+	if(devnum & 0x80)
+	     return(-1);
+	mech2bus = (UCHAR)((devnum & 0xff00) >> 8);	  /* Bus num */
+	mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3;	  /* Dev num */
+	mech2Agent |= 0xc0;
+	mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07;  /* Fun num */
+	mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
+    }
+    else	/* use mech #1 method */
+    {
+	mech1addr = 0x80000000 | ((ULONG)devnum << 8);
+    }
+    return(0);
+}
+
+/***********************************************************************
+ * Function : static int DC390_init (struct Scsi_Host *host)
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure/
+ *
+ * Preconditions : when this function is called, the chip_type
+ *	field of the pACB structure MUST have been set.
+ ***********************************************************************/
+
+static int
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+{
+    PSH   psh;
+    PACB  pACB;
+
+    if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+    {
+	psh = scsi_register( psht, sizeof(DC390_ACB) );
+	if( !psh )
+	    return( -1 );
+	if( !pSH_start )
+	{
+	    pSH_start = psh;
+	    pSH_current = psh;
+	}
+	else
+	{
+	    pSH_current->next = psh;
+	    pSH_current = psh;
+	}
+
+#ifdef DC390_DEBUG0
+	printk("DC390: pSH = %8x,", (UINT) psh);
+	printk("DC390: Index %02i,", index);
+#endif
+
+	DC390_initACB( psh, io_port, Irq, index );
+	if( !DC390_initAdapter( psh, io_port, Irq, index ) )
+	{
+	    pACB = (PACB) psh->hostdata;
+	    if( !pACB_start )
+	    {
+		pACB_start = pACB;
+		pACB_current = pACB;
+		pACB->pNextACB = (PACB) -1;
+	    }
+	    else
+	    {
+		pACB_current->pNextACB = pACB;
+		pACB_current = pACB;
+		pACB->pNextACB = (PACB)  -1;
+	    }
+
+#ifdef DC390_DEBUG0
+	printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
+	      (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
+	printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
+	      sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
+#endif
+
+	}
+	else
+	{
+	    pSH_start = NULL;
+	    scsi_unregister( psh );
+	    return( -1 );
+	}
+	return( 0 );
+    }
+    else
+    {
+	printk("DC390_init: EEPROM reading error!\n");
+	return( -1 );
+    }
+}
+
+
+/***********************************************************************
+ * Function : int DC390_detect(Scsi_Host_Template *psht)
+ *
+ * Purpose : detects and initializes AMD53C974 SCSI chips
+ *	     that were autoprobed, overridden on the LILO command line,
+ *	     or specified at compile time.
+ *
+ * Inputs : psht - template for this SCSI adapter
+ *
+ * Returns : number of host adapters detected
+ *
+ ***********************************************************************/
+
+int
+DC390_detect(Scsi_Host_Template *psht)
+{
+#ifdef FOR_PCI_OK
+    UCHAR   pci_bus, pci_device_fn;
+    int     error = 0;
+    USHORT  chipType = 0;
+    USHORT  i;
+#endif
+
+    UCHAR   irq;
+    UCHAR   istatus;
+#ifndef VERSION_ELF_1_2_13
+    UINT    io_port;
+#else
+    ULONG   io_port;
+#endif
+    USHORT  adaptCnt = 0;	/* Number of boards detected */
+    USHORT  pci_index = 0;	/* Device index to PCI BIOS calls */
+    USHORT  MechNum, BusDevFunNum;
+    ULONG   wlval;
+
+#ifndef VERSION_ELF_1_2_13
+    psht->proc_dir = &proc_scsi_tmscsim;
+#endif
+
+    InitialTime = 1;
+    pSHT_start = psht;
+    pACB_start = NULL;
+
+    MechNum = 1;
+    for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
+    {
+	BusDevFunNum = 0;
+	for (; adaptCnt < MAX_ADAPTER_NUM ;)
+	{
+	    if( !DC390_ToMech( MechNum, BusDevFunNum) )
+	    {
+		 wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
+		 if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
+				PCI_VENDOR_ID_AMD) )
+		 {
+		    io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
+		    irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
+#ifdef DC390_DEBUG0
+		printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+		    if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
+		    {
+			adaptCnt++;
+			pci_index++;
+			istatus = inb( (USHORT)io_port+INT_Status );	/* Reset Pending INT */
+#ifdef DC390_DEBUG0
+		printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
+#endif
+		    }
+		 }
+	    }
+	    if( BusDevFunNum != 0xfff8 )
+		BusDevFunNum += 8;	    /* next device # */
+	    else
+		break;
+	}
+    }
+
+#ifdef FOR_PCI_OK
+    if ( pcibios_present() )
+    {
+	for (i = 0; i < MAX_ADAPTER_NUM; ++i)
+	{
+	    if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
+				PCI_DEVICE_ID_AMD53C974,
+				pci_index, &pci_bus, &pci_device_fn) )
+	    {
+		chipType = PCI_DEVICE_ID_AMD53C974;
+		pci_index++;
+	    }
+
+	    if( chipType )
+	    {
+
+		error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+						  PCI_BASE_ADDRESS_0, &io_port);
+		error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
+						  PCI_INTERRUPT_LINE, &irq);
+		if( error )
+		{
+		    printk("DC390_detect: reading configuration registers error!\n");
+		    InitialTime = 0;
+		    return( 0 );
+		}
+
+		(USHORT) io_port = (USHORT) io_port & 0xFFFE;
+#ifdef DC390_DEBUG0
+		printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+		if( !DC390_init(psht, io_port, irq, i) )
+		    adaptCnt++;
+		chipType = 0;
+	    }
+	    else
+		break;
+	}
+    }
+#endif
+
+    InitialTime = 0;
+    adapterCnt = adaptCnt;
+    return( adaptCnt );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+
+/********************************************************************
+ * Function: tmscsim_set_info()
+ *
+ * Purpose: Set adapter info (!)
+ *
+ * Not yet implemented
+ *
+ *******************************************************************/
+
+int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+  return(-ENOSYS);  /* Currently this is a no-op */
+}
+
+/********************************************************************
+ * Function: tmscsim_proc_info(char* buffer, char **start,
+ *			     off_t offset, int length, int hostno, int inout)
+ *
+ * Purpose: return SCSI Adapter/Device Info
+ *
+ * Input: buffer: Pointer to a buffer where to write info
+ *	  start :
+ *	  offset:
+ *	  hostno: Host adapter index
+ *	  inout : Read (=0) or set(!=0) info
+ *
+ * Output: buffer: contains info
+ *	   length; length of info in buffer
+ *
+ * return value: length
+ *
+ ********************************************************************/
+
+/* KG: proc_info taken from driver aha152x.c */
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+#define YESNO(YN)\
+if (YN) SPRINTF(" Yes ");\
+else SPRINTF(" No  ")
+
+int tmscsim_proc_info(char *buffer, char **start,
+		      off_t offset, int length, int hostno, int inout)
+{
+  int dev, spd, spd1;
+  char *pos = buffer;
+  PSH shpnt;
+  PACB acbpnt;
+  PDCB dcbpnt;
+  unsigned long flags;
+/*  Scsi_Cmnd *ptr; */
+
+  acbpnt = pACB_start;
+
+  while(acbpnt != (PACB)-1)
+     {
+	shpnt = acbpnt->pScsiHost;
+	if (shpnt->host_no == hostno) break;
+	acbpnt = acbpnt->pNextACB;
+     }
+
+  if (acbpnt == (PACB)-1) return(-ESRCH);
+  if(!shpnt) return(-ESRCH);
+
+  if(inout) // Has data been written to the file ?
+    return(tmscsim_set_info(buffer, length, shpnt));
+
+  SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
+  SPRINTF("Driver Version 1.10, 1996/12/05\n");
+
+  save_flags(flags);
+  cli();
+
+  SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
+  SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
+  SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
+  SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+
+  SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
+  SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+
+  SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+
+  SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+
+  SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+
+  dcbpnt = acbpnt->pLinkDCB;
+  for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+     {
+      SPRINTF("%02i %02i  %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
+      YESNO(dcbpnt->DevMode & PARITY_CHK_);
+      YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
+      YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
+      YESNO(dcbpnt->DevMode & SEND_START_);
+      YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
+      SPRINTF("  %03i ns ", (dcbpnt->NegoPeriod) << 2);
+      if (dcbpnt->SyncOffset & 0x0f)
+      {
+	 spd = 1000/(dcbpnt->NegoPeriod <<2);
+	 spd1 = 1000%(dcbpnt->NegoPeriod <<2);
+	 spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
+	 SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+      }
+      else SPRINTF("\n");
+      /* Add more info ...*/
+      dcbpnt = dcbpnt->pNextDCB;
+     }
+
+  restore_flags(flags);
+  *start = buffer + offset;
+
+  if (pos - buffer < offset)
+    return 0;
+  else if (pos - buffer - offset < length)
+    return pos - buffer - offset;
+  else
+    return length;
+}
+#endif /* VERSION_ELF_1_2_13 */
+
+
+#ifdef MODULE
+
+/***********************************************************************
+ * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the SCSI chip.
+ *	     Use prior to dumping core, unloading the driver, etc.
+ *
+ * Returns : 0 on success
+ ***********************************************************************/
+static int
+DC390_shutdown (struct Scsi_Host *host)
+{
+    UCHAR    bval;
+    USHORT   ioport;
+    unsigned long flags;
+    PACB pACB = (PACB)(host->hostdata);
+
+    ioport = (unsigned int) pACB->IOPortBase;
+
+    save_flags (flags);
+    cli();
+
+/*  pACB->soft_reset(host); */
+
+#ifdef DC390_DEBUG0
+    printk("DC390: shutdown,");
+#endif
+
+    bval = inb(ioport+CtrlReg1);
+    bval |= DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
+    DC390_ResetSCSIBus( pACB );
+
+    restore_flags (flags);
+    return( 0 );
+}
+
+
+int DC390_release(struct Scsi_Host *host)
+{
+    int irq_count;
+    struct Scsi_Host *tmp;
+
+    DC390_shutdown (host);
+
+    if (host->irq != IRQ_NONE)
+    {
+	for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+	{
+	    if ( tmp->irq == host->irq )
+		++irq_count;
+	}
+	if (irq_count == 1)
+	 {
+#ifdef DC390_DEBUG0
+	    printk("DC390: Free IRQ %i.",host->irq);
+#endif
+#ifndef VERSION_ELF_1_2_13
+	    free_irq(host->irq,NULL);
+#else
+	    free_irq(host->irq);
+#endif
+	 }
+    }
+
+    release_region(host->io_port,host->n_io_port);
+
+    return( 1 );
+}
+
+Scsi_Host_Template driver_template = DC390_T;
+#include "scsi_module.c"
+#endif /* def MODULE */
+
diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.1.36/linux/drivers/scsi/tmscsim.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/tmscsim.h	Mon May 12 10:35:42 1997
@@ -0,0 +1,680 @@
+/***********************************************************************
+;*	File Name : TMSCSIM.H					       *
+;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
+;*		    Device Driver				       *
+;***********************************************************************/
+
+#ifndef TMSCSIM_H
+#define TMSCSIM_H
+
+#define IRQ_NONE 255
+
+typedef unsigned char	UCHAR;
+typedef unsigned short	USHORT;
+typedef unsigned long	ULONG;
+typedef unsigned int	UINT;
+
+typedef UCHAR		*PUCHAR;
+typedef USHORT		*PUSHORT;
+typedef ULONG		*PULONG;
+typedef Scsi_Host_Template  *PSHT;
+typedef struct Scsi_Host    *PSH;
+typedef Scsi_Device	*PSCSIDEV;
+typedef Scsi_Cmnd	*PSCSICMD;
+typedef void		*PVOID;
+typedef struct scatterlist  *PSGL, SGL;
+
+
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _SyncMsg
+{
+UCHAR		ExtendMsg;
+UCHAR		ExtMsgLen;
+UCHAR		SyncXferReq;
+UCHAR		Period;
+UCHAR		ReqOffset;
+} SyncMsg;
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _Capacity
+{
+ULONG		BlockCount;
+ULONG		BlockLength;
+} Capacity;
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _SGentry
+{
+ULONG		SGXferDataPtr;
+ULONG		SGXferDataLen;
+} SGentry;
+
+typedef  struct  _SGentry1
+{
+ULONG		SGXLen;
+ULONG		SGXPtr;
+} SGentry1, *PSGE;
+
+
+#define MAX_ADAPTER_NUM 	4
+#define MAX_DEVICES		10
+#define MAX_SG_LIST_BUF 	16
+#define MAX_CMD_QUEUE		20
+#define MAX_CMD_PER_LUN 	8
+#define MAX_SCSI_ID		8
+#define MAX_SRB_CNT		MAX_CMD_QUEUE+4
+#define END_SCAN		2
+
+#define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
+
+/*
+;-----------------------------------------------------------------------
+; SCSI Request Block
+;-----------------------------------------------------------------------
+*/
+struct	_SRB
+{
+UCHAR		CmdBlock[12];
+
+struct _SRB	*pNextSRB;
+struct _DCB	*pSRBDCB;
+PSCSICMD	pcmd;
+PSGL		pSegmentList;
+
+ULONG		PhysSRB;
+ULONG		TotalXferredLen;
+ULONG		SGPhysAddr;	/*;a segment starting address */
+ULONG		SGToBeXferLen;	/*; to be xfer length */
+
+SGL		Segmentx;	/* make a one entry of S/G list table */
+
+PUCHAR		pMsgPtr;
+USHORT		SRBState;
+USHORT		Revxx2; 	/* ??? */
+
+UCHAR		MsgInBuf[6];
+UCHAR		MsgOutBuf[6];
+
+UCHAR		AdaptStatus;
+UCHAR		TargetStatus;
+UCHAR		MsgCnt;
+UCHAR		EndMessage;
+UCHAR		TagNumber;
+UCHAR		SGcount;
+UCHAR		SGIndex;
+UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
+
+UCHAR		SRBStatus;
+UCHAR		RetryCnt;
+UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
+				/*; b4-settimeout,b5-Residual valid */
+UCHAR		ScsiCmdLen;
+UCHAR		ScsiPhase;
+UCHAR		Reserved3[3];	/*;for dword alignment */
+ULONG		Segment0[2];
+ULONG		Segment1[2];
+};
+
+typedef  struct  _SRB	 DC390_SRB, *PSRB;
+
+/*
+;-----------------------------------------------------------------------
+; Device Control Block
+;-----------------------------------------------------------------------
+*/
+struct	_DCB
+{
+struct _DCB	*pNextDCB;
+struct _ACB	*pDCBACB;
+
+PSCSICMD	pQIORBhead;
+PSCSICMD	pQIORBtail;
+PSCSICMD	AboIORBhead;
+PSCSICMD	AboIORBtail;
+USHORT		QIORBCnt;
+USHORT		AboIORBcnt;
+
+PSRB		pWaitingSRB;
+PSRB		pWaitLast;
+PSRB		pGoingSRB;
+PSRB		pGoingLast;
+PSRB		pActiveSRB;
+USHORT		GoingSRBCnt;
+USHORT		WaitSRBCnt;	/* ??? */
+
+ULONG		TagMask;
+
+USHORT		MaxCommand;
+USHORT		AdaptIndex;	/*; UnitInfo struc start */
+USHORT		UnitIndex;	/*; nth Unit on this card */
+UCHAR		UnitSCSIID;	/*; SCSI Target ID  (SCSI Only) */
+UCHAR		UnitSCSILUN;	/*; SCSI Log.  Unit (SCSI Only) */
+
+UCHAR		IdentifyMsg;
+UCHAR		CtrlR1;
+UCHAR		CtrlR3;
+UCHAR		CtrlR4;
+
+UCHAR		InqDataBuf[8];
+UCHAR		CapacityBuf[8];
+UCHAR		DevMode;
+UCHAR		AdpMode;
+UCHAR		SyncMode;	/*; 0:async mode */
+UCHAR		NegoPeriod;	/*;for nego. */
+UCHAR		SyncPeriod;	/*;for reg. */
+UCHAR		SyncOffset;	/*;for reg. and nego.(low nibble) */
+UCHAR		UnitCtrlFlag;
+UCHAR		DCBFlag;
+UCHAR		DevType;
+UCHAR		Reserved2[3];	/*;for dword alignment */
+};
+
+typedef  struct  _DCB	 DC390_DCB, *PDCB;
+/*
+;-----------------------------------------------------------------------
+; Adapter Control Block
+;-----------------------------------------------------------------------
+*/
+struct	_ACB
+{
+ULONG		PhysACB;
+PSH		pScsiHost;
+struct _ACB	*pNextACB;
+USHORT		IOPortBase;
+USHORT		Revxx1; 	/* ??? */
+
+PDCB		pLinkDCB;
+PDCB		pDCBRunRobin;
+PDCB		pActiveDCB;
+PDCB		pDCB_free;
+PSRB		pFreeSRB;
+PSRB		pTmpSRB;
+USHORT		SRBCount;
+USHORT		AdapterIndex;	/*; nth Adapter this driver */
+USHORT		max_id;
+USHORT		max_lun;
+
+UCHAR		msgin123[4];
+UCHAR		status;
+UCHAR		AdaptSCSIID;	/*; Adapter SCSI Target ID */
+UCHAR		AdaptSCSILUN;	/*; Adapter SCSI LUN */
+UCHAR		DeviceCnt;
+UCHAR		IRQLevel;
+UCHAR		TagMaxNum;
+UCHAR		ACBFlag;
+UCHAR		Gmode2;
+UCHAR		LUNchk;
+UCHAR		scan_devices;
+UCHAR		HostID_Bit;
+UCHAR		Reserved1[1];	/*;for dword alignment */
+UCHAR		DCBmap[MAX_SCSI_ID];
+DC390_DCB	DCB_array[MAX_DEVICES]; 	/* +74h,  Len=3E8 */
+DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* +45Ch, Len=	*/
+DC390_SRB	TmpSRB;
+};
+
+typedef  struct  _ACB	 DC390_ACB, *PACB;
+
+/*;-----------------------------------------------------------------------*/
+
+
+#define BIT31	0x80000000
+#define BIT30	0x40000000
+#define BIT29	0x20000000
+#define BIT28	0x10000000
+#define BIT27	0x08000000
+#define BIT26	0x04000000
+#define BIT25	0x02000000
+#define BIT24	0x01000000
+#define BIT23	0x00800000
+#define BIT22	0x00400000
+#define BIT21	0x00200000
+#define BIT20	0x00100000
+#define BIT19	0x00080000
+#define BIT18	0x00040000
+#define BIT17	0x00020000
+#define BIT16	0x00010000
+#define BIT15	0x00008000
+#define BIT14	0x00004000
+#define BIT13	0x00002000
+#define BIT12	0x00001000
+#define BIT11	0x00000800
+#define BIT10	0x00000400
+#define BIT9	0x00000200
+#define BIT8	0x00000100
+#define BIT7	0x00000080
+#define BIT6	0x00000040
+#define BIT5	0x00000020
+#define BIT4	0x00000010
+#define BIT3	0x00000008
+#define BIT2	0x00000004
+#define BIT1	0x00000002
+#define BIT0	0x00000001
+
+/*;---UnitCtrlFlag */
+#define UNIT_ALLOCATED	BIT0
+#define UNIT_INFO_CHANGED BIT1
+#define FORMATING_MEDIA BIT2
+#define UNIT_RETRY	BIT3
+
+/*;---UnitFlags */
+#define DASD_SUPPORT	BIT0
+#define SCSI_SUPPORT	BIT1
+#define ASPI_SUPPORT	BIT2
+
+/*;----SRBState machine definition */
+#define SRB_FREE	0
+#define SRB_WAIT	BIT0
+#define SRB_READY	BIT1
+#define SRB_MSGOUT	BIT2	/*;arbitration+msg_out 1st byte*/
+#define SRB_MSGIN	BIT3
+#define SRB_MSGIN_MULTI BIT4
+#define SRB_COMMAND	BIT5
+#define SRB_START_	BIT6	/*;arbitration+msg_out+command_out*/
+#define SRB_DISCONNECT	BIT7
+#define SRB_DATA_XFER	BIT8
+#define SRB_XFERPAD	BIT9
+#define SRB_STATUS	BIT10
+#define SRB_COMPLETED	BIT11
+#define SRB_ABORT_SENT	BIT12
+#define DO_SYNC_NEGO	BIT13
+#define SRB_UNEXPECT_RESEL BIT14
+
+/*;---ACBFlag */
+#define RESET_DEV	BIT0
+#define RESET_DETECT	BIT1
+#define RESET_DONE	BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_	BIT0
+
+/*;---SRBstatus */
+#define SRB_OK		BIT0
+#define ABORTION	BIT1
+#define OVER_RUN	BIT2
+#define UNDER_RUN	BIT3
+#define PARITY_ERROR	BIT4
+#define SRB_ERROR	BIT5
+
+/*;---SRBFlag */
+#define DATAOUT 	BIT7
+#define DATAIN		BIT6
+#define RESIDUAL_VALID	BIT5
+#define ENABLE_TIMER	BIT4
+#define RESET_DEV0	BIT2
+#define ABORT_DEV	BIT1
+#define AUTO_REQSENSE	BIT0
+
+/*;---Adapter status */
+#define H_STATUS_GOOD	 0
+#define H_SEL_TIMEOUT	 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD	 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB  0x19
+#define H_BAD_CCB_OR_SG  0x1A
+#define H_ABORT 	 0x0FF
+
+/*; SCSI Status byte codes*/
+#define SCSI_STAT_GOOD		0x0	/*;  Good status */
+#define SCSI_STAT_CHECKCOND	0x02	/*;  SCSI Check Condition */
+#define SCSI_STAT_CONDMET	0x04	/*;  Condition Met */
+#define SCSI_STAT_BUSY		0x08	/*;  Target busy status */
+#define SCSI_STAT_INTER 	0x10	/*;  Intermediate status */
+#define SCSI_STAT_INTERCONDMET	0x14	/*;  Intermediate condition met */
+#define SCSI_STAT_RESCONFLICT	0x18	/*;  Reservation conflict */
+#define SCSI_STAT_CMDTERM	0x22	/*;  Command Terminated */
+#define SCSI_STAT_QUEUEFULL	0x28	/*;  Queue Full */
+
+#define SCSI_STAT_UNEXP_BUS_F	0xFD	/*;  Unexpect Bus Free */
+#define SCSI_STAT_BUS_RST_DETECT 0xFE	/*;  Scsi Bus Reset detected */
+#define SCSI_STAT_SEL_TIMEOUT	0xFF	/*;  Selection Time out */
+
+/*;---Sync_Mode */
+#define SYNC_DISABLE	0
+#define SYNC_ENABLE	BIT0
+#define SYNC_NEGO_DONE	BIT1
+#define WIDE_ENABLE	BIT2
+#define WIDE_NEGO_DONE	BIT3
+#define EN_TAG_QUEUING	BIT4
+#define EN_ATN_STOP	BIT5
+
+#define SYNC_NEGO_OFFSET 15
+
+/*;---SCSI bus phase*/
+#define SCSI_DATA_OUT	0
+#define SCSI_DATA_IN	1
+#define SCSI_COMMAND	2
+#define SCSI_STATUS_	3
+#define SCSI_NOP0	4
+#define SCSI_NOP1	5
+#define SCSI_MSG_OUT	6
+#define SCSI_MSG_IN	7
+
+/*;----SCSI MSG BYTE*/
+#define MSG_COMPLETE		0x00
+#define MSG_EXTENDED		0x01
+#define MSG_SAVE_PTR		0x02
+#define MSG_RESTORE_PTR 	0x03
+#define MSG_DISCONNECT		0x04
+#define MSG_INITIATOR_ERROR	0x05
+#define MSG_ABORT		0x06
+#define MSG_REJECT_		0x07
+#define MSG_NOP 		0x08
+#define MSG_PARITY_ERROR	0x09
+#define MSG_LINK_CMD_COMPL	0x0A
+#define MSG_LINK_CMD_COMPL_FLG	0x0B
+#define MSG_BUS_RESET		0x0C
+#define MSG_ABORT_TAG		0x0D
+#define MSG_SIMPLE_QTAG 	0x20
+#define MSG_HEAD_QTAG		0x21
+#define MSG_ORDER_QTAG		0x22
+#define MSG_IDENTIFY		0x80
+#define MSG_HOST_ID		0x0C0
+
+/*;----SCSI STATUS BYTE*/
+#define STATUS_GOOD		0x00
+#define CHECK_CONDITION_	0x02
+#define STATUS_BUSY		0x08
+#define STATUS_INTERMEDIATE	0x10
+#define RESERVE_CONFLICT	0x18
+
+/* cmd->result */
+#define STATUS_MASK_		0xFF
+#define MSG_MASK		0xFF00
+#define RETURN_MASK		0xFF0000
+
+/*
+**  Inquiry Data format
+*/
+
+typedef struct	_SCSIInqData { /* INQ */
+
+	UCHAR	 DevType;		/* Periph Qualifier & Periph Dev Type*/
+	UCHAR	 RMB_TypeMod;		/* rem media bit & Dev Type Modifier */
+	UCHAR	 Vers;			/* ISO, ECMA, & ANSI versions	     */
+	UCHAR	 RDF;			/* AEN, TRMIOP, & response data format*/
+	UCHAR	 AddLen;		/* length of additional data	     */
+	UCHAR	 Res1;			/* reserved			     */
+	UCHAR	 Res2;			/* reserved			     */
+	UCHAR	 Flags; 		/* RelADr,Wbus32,Wbus16,Sync,etc.    */
+	UCHAR	 VendorID[8];		/* Vendor Identification	     */
+	UCHAR	 ProductID[16]; 	/* Product Identification	     */
+	UCHAR	 ProductRev[4]; 	/* Product Revision		     */
+
+
+} SCSI_INQDATA, *PSCSI_INQDATA;
+
+
+/*  Inquiry byte 0 masks */
+
+
+#define SCSI_DEVTYPE	    0x1F      /* Peripheral Device Type 	    */
+#define SCSI_PERIPHQUAL     0xE0      /* Peripheral Qualifier		    */
+
+
+/*  Inquiry byte 1 mask */
+
+#define SCSI_REMOVABLE_MEDIA  0x80    /* Removable Media bit (1=removable)  */
+
+
+/*  Peripheral Device Type definitions */
+
+#define SCSI_DASD		 0x00	   /* Direct-access Device	   */
+#define SCSI_SEQACESS		 0x01	   /* Sequential-access device	   */
+#define SCSI_PRINTER		 0x02	   /* Printer device		   */
+#define SCSI_PROCESSOR		 0x03	   /* Processor device		   */
+#define SCSI_WRITEONCE		 0x04	   /* Write-once device 	   */
+#define SCSI_CDROM		 0x05	   /* CD-ROM device		   */
+#define SCSI_SCANNER		 0x06	   /* Scanner device		   */
+#define SCSI_OPTICAL		 0x07	   /* Optical memory device	   */
+#define SCSI_MEDCHGR		 0x08	   /* Medium changer device	   */
+#define SCSI_COMM		 0x09	   /* Communications device	   */
+#define SCSI_NODEV		 0x1F	   /* Unknown or no device type    */
+
+/*
+** Inquiry flag definitions (Inq data byte 7)
+*/
+
+#define SCSI_INQ_RELADR       0x80    /* device supports relative addressing*/
+#define SCSI_INQ_WBUS32       0x40    /* device supports 32 bit data xfers  */
+#define SCSI_INQ_WBUS16       0x20    /* device supports 16 bit data xfers  */
+#define SCSI_INQ_SYNC	      0x10    /* device supports synchronous xfer   */
+#define SCSI_INQ_LINKED       0x08    /* device supports linked commands    */
+#define SCSI_INQ_CMDQUEUE     0x02    /* device supports command queueing   */
+#define SCSI_INQ_SFTRE	      0x01    /* device supports soft resets */
+
+
+/*
+;==========================================================
+; EEPROM byte offset
+;==========================================================
+*/
+typedef  struct  _EEprom
+{
+UCHAR	EE_MODE1;
+UCHAR	EE_SPEED;
+UCHAR	xx1;
+UCHAR	xx2;
+} EEprom, *PEEprom;
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2	65
+#define EE_DELAY	66
+#define EE_TAG_CMD_NUM	67
+
+/*; EE_MODE1 bits definition*/
+#define PARITY_CHK_	BIT0
+#define SYNC_NEGO_	BIT1
+#define EN_DISCONNECT_	BIT2
+#define SEND_START_	BIT3
+#define TAG_QUEUING_	BIT4
+
+/*; EE_MODE2 bits definition*/
+#define MORE2_DRV	BIT0
+#define GREATER_1G	BIT1
+#define RST_SCSI_BUS	BIT2
+#define ACTIVE_NEGATION BIT3
+#define NO_SEEK 	BIT4
+#define LUN_CHECK	BIT5
+
+#define ENABLE_CE	1
+#define DISABLE_CE	0
+#define EEPROM_READ	0x80
+
+/*
+;==========================================================
+;	AMD 53C974 Registers bit Definition
+;==========================================================
+*/
+/*
+;====================
+; SCSI Register
+;====================
+*/
+
+/*; Command Reg.(+0CH) */
+#define DMA_COMMAND		BIT7
+#define NOP_CMD 		0
+#define CLEAR_FIFO_CMD		1
+#define RST_DEVICE_CMD		2
+#define RST_SCSI_BUS_CMD	3
+#define INFO_XFER_CMD		0x10
+#define INITIATOR_CMD_CMPLTE	0x11
+#define MSG_ACCEPTED_CMD	0x12
+#define XFER_PAD_BYTE		0x18
+#define SET_ATN_CMD		0x1A
+#define RESET_ATN_CMD		0x1B
+#define SELECT_W_ATN		0x42
+#define SEL_W_ATN_STOP		0x43
+#define EN_SEL_RESEL		0x44
+#define SEL_W_ATN2		0x46
+#define DATA_XFER_CMD		INFO_XFER_CMD
+
+
+/*; SCSI Status Reg.(+10H) */
+#define INTERRUPT		BIT7
+#define ILLEGAL_OP_ERR		BIT6
+#define PARITY_ERR		BIT5
+#define COUNT_2_ZERO		BIT4
+#define GROUP_CODE_VALID	BIT3
+#define SCSI_PHASE_MASK 	(BIT2+BIT1+BIT0)
+
+/*; Interrupt Status Reg.(+14H) */
+#define SCSI_RESET		BIT7
+#define INVALID_CMD		BIT6
+#define DISCONNECTED		BIT5
+#define SERVICE_REQUEST 	BIT4
+#define SUCCESSFUL_OP		BIT3
+#define RESELECTED		BIT2
+#define SEL_ATTENTION		BIT1
+#define SELECTED		BIT0
+
+/*; Internal State Reg.(+18H) */
+#define SYNC_OFFSET_FLAG	BIT3
+#define INTRN_STATE_MASK	(BIT2+BIT1+BIT0)
+
+/*; Clock Factor Reg.(+24H) */
+#define CLK_FREQ_40MHZ		0
+#define CLK_FREQ_35MHZ		(BIT2+BIT1+BIT0)
+#define CLK_FREQ_30MHZ		(BIT2+BIT1)
+#define CLK_FREQ_25MHZ		(BIT2+BIT0)
+#define CLK_FREQ_20MHZ		BIT2
+#define CLK_FREQ_15MHZ		(BIT1+BIT0)
+#define CLK_FREQ_10MHZ		BIT1
+
+/*; Control Reg. 1(+20H) */
+#define EXTENDED_TIMING 	BIT7
+#define DIS_INT_ON_SCSI_RST	BIT6
+#define PARITY_ERR_REPO 	BIT4
+#define SCSI_ID_ON_BUS		(BIT2+BIT1+BIT0)
+
+/*; Control Reg. 2(+2CH) */
+#define EN_FEATURE		BIT6
+#define EN_SCSI2_CMD		BIT3
+
+/*; Control Reg. 3(+30H) */
+#define ID_MSG_CHECK		BIT7
+#define EN_QTAG_MSG		BIT6
+#define EN_GRP2_CMD		BIT5
+#define FAST_SCSI		BIT4	/* ;10MB/SEC */
+#define FAST_CLK		BIT3	/* ;25 - 40 MHZ */
+
+/*; Control Reg. 4(+34H) */
+#define EATER_12NS		0
+#define EATER_25NS		BIT7
+#define EATER_35NS		BIT6
+#define EATER_0NS		(BIT7+BIT6)
+#define NEGATE_REQACKDATA	BIT2
+#define NEGATE_REQACK		BIT3
+/*
+;====================
+; DMA Register
+;====================
+*/
+/*; DMA Command Reg.(+40H) */
+#define READ_DIRECTION		BIT7
+#define WRITE_DIRECTION 	0
+#define EN_DMA_INT		BIT6
+#define MAP_TO_MDL		BIT5
+#define DIAGNOSTIC		BIT4
+#define DMA_IDLE_CMD		0
+#define DMA_BLAST_CMD		BIT0
+#define DMA_ABORT_CMD		BIT1
+#define DMA_START_CMD		(BIT1+BIT0)
+
+/*; DMA Status Reg.(+54H) */
+#define PCI_MS_ABORT		BIT6
+#define BLAST_COMPLETE		BIT5
+#define SCSI_INTERRUPT		BIT4
+#define DMA_XFER_DONE		BIT3
+#define DMA_XFER_ABORT		BIT2
+#define DMA_XFER_ERROR		BIT1
+#define POWER_DOWN		BIT0
+
+/*
+; DMA SCSI Bus and Ctrl.(+70H)
+;EN_INT_ON_PCI_ABORT
+*/
+
+/*
+;==========================================================
+; SCSI Chip register address offset
+;==========================================================
+*/
+#define CtcReg_Low	0x00
+#define CtcReg_Mid	0x04
+#define ScsiFifo	0x08
+#define ScsiCmd 	0x0C
+#define Scsi_Status	0x10
+#define INT_Status	0x14
+#define Sync_Period	0x18
+#define Sync_Offset	0x1C
+#define CtrlReg1	0x20
+#define Clk_Factor	0x24
+#define CtrlReg2	0x2C
+#define CtrlReg3	0x30
+#define CtrlReg4	0x34
+#define CtcReg_High	0x38
+#define DMA_Cmd 	0x40
+#define DMA_XferCnt	0x44
+#define DMA_XferAddr	0x48
+#define DMA_Wk_ByteCntr 0x4C
+#define DMA_Wk_AddrCntr 0x50
+#define DMA_Status	0x54
+#define DMA_MDL_Addr	0x58
+#define DMA_Wk_MDL_Cntr 0x5C
+#define DMA_ScsiBusCtrl 0x70
+
+#define StcReg_Low	CtcReg_Low
+#define StcReg_Mid	CtcReg_Mid
+#define Scsi_Dest_ID	Scsi_Status
+#define Scsi_TimeOut	INT_Status
+#define Intern_State	Sync_Period
+#define Current_Fifo	Sync_Offset
+#define StcReg_High	CtcReg_High
+
+#define am_target	Scsi_Status
+#define am_timeout	INT_Status
+#define am_seq_step	Sync_Period
+#define am_fifo_count	Sync_Offset
+
+
+#define DC390_read8(address)			       \
+	inb(DC390_ioport + (address)))
+
+#define DC390_read16(address)			       \
+	inw(DC390_ioport + (address)))
+
+#define DC390_read32(address)			       \
+	inl(DC390_ioport + (address)))
+
+#define DC390_write8(address,value)		       \
+	outb((value), DC390_ioport + (address)))
+
+#define DC390_write16(address,value)		       \
+	outw((value), DC390_ioport + (address)))
+
+#define DC390_write32(address,value)		       \
+	outl((value), DC390_ioport + (address)))
+
+
+/* Configuration method #1 */
+#define PCI_CFG1_ADDRESS_REG		0xcf8
+#define PCI_CFG1_DATA_REG		0xcfc
+#define PCI_CFG1_ENABLE 		0x80000000
+#define PCI_CFG1_TUPPLE(bus, device, function, register)		\
+	(PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | 		\
+	(((device) << 11) & 0xf800) | (((function) << 8) & 0x700)|	\
+	(((register) << 2) & 0xfc))
+
+/* Configuration method #2 */
+#define PCI_CFG2_ENABLE_REG		0xcf8
+#define PCI_CFG2_FORWARD_REG		0xcfa
+#define PCI_CFG2_ENABLE 		0x0f0
+#define PCI_CFG2_TUPPLE(function)					\
+	(PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
+
+
+#endif /* TMSCSIM_H */
diff -u --recursive --new-file v2.1.36/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.36/linux/drivers/sound/Config.in	Tue Mar  4 10:25:24 1997
+++ linux/drivers/sound/Config.in	Mon May 12 10:35:42 1997
@@ -1,15 +1,277 @@
-#
-# Sound driver configuration
-#
-#--------
-# There is another confic script which is compatible with rest of
-# the kernel. It can be activated by running 'make mkscript' in this
-# directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
-#--------
-#
-$MAKE -C drivers/sound config || exit 1
+bool 'ProAudioSpectrum 16 support' CONFIG_PAS
+bool '_TRUE_ Sound Blaster (SB, SBPro, SB16/32/64, ESS, Jazz16) support' CONFIG_SB
+bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
+bool 'Gravis Ultrasound support' CONFIG_GUS
+bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
+bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
+bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
+bool 'GUS MAX support' CONFIG_GUSMAX
+bool 'Microsoft Sound System support' CONFIG_MSS
+bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
+bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
+bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16
+bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
+bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
+bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
+
+if [ "$CONFIG_AEDSP16" = "y" ]; then
+hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'Enter -1 to the following question if you have something else such as SB16/32.'
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
+fi
+
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with Maui.'
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
+fi
+
+
+if [ "$CONFIG_PSS" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with PSS cards.'
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS I/O base 220 or 240' PSS_BASE 220
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
+fi
 
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
+fi
+
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with AudioTrix.'
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
+fi
+#
+$MAKE -C drivers/sound kernelconfig || exit 1
 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
 
 if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
diff -u --recursive --new-file v2.1.36/linux/fs/affs/Changes linux/fs/affs/Changes
--- v2.1.36/linux/fs/affs/Changes	Wed Dec 31 16:00:00 1969
+++ linux/fs/affs/Changes	Mon May 12 10:35:42 1997
@@ -0,0 +1,95 @@
+(Note: I consider version numbers as cheap. That means
+that I do not like numbers like 0.1 and the like for
+things that can be used since quite some time. But
+then, 3.1 doesn't mean 'perfectly stable', too.)
+
+Known bugs:
+-----------
+
+- Doesn't work on the alpha. The only 64/32-bit
+  problem that I'm aware of (pointer/int conversion
+  in readdir()) gives compiler warnings but is
+  apparently not causing the failure, as directory
+  reads basically work (but all files are of size 0).
+  Alas, I've got no alpha to debug. :-(
+- If an affs mounted filesystem is exported via
+  nfs, it cannot be written to. No networking to
+  test that, either. :-(
+
+Please direct bug reports to: hjw@zvw.de
+
+Version 3.4
+-----------
+
+- Hash chains are now sorted by block numbers.
+  (Thanks to Kars de Jong for finding this.)
+- Removed all unnecessary external symbols.
+
+Version 3.3
+-----------
+
+- Tried to make all types 'correct' and consistent.
+- Errors and warnings are now reported via a
+  function. They are all prefixed by a severity
+  and have the same appearance:
+    "AFFS: <function>: <error message>"
+  (There's one exception to this, as in that function
+  is no pointer to the super block available.)
+- The filesystem is remounted read-only after an
+  error.
+- The names of newly created filesystem objects are
+  now checked for validity.
+- Minor cleanups in comments.
+- Added this Changes file. At last!
+
+Version 3.2
+-----------
+
+- Extension block cache: Reading/writing of huge files
+  (several MB) is much faster (of course the added
+  overhead slows down opening, but this is hardly
+  noticeable).
+- The same get_block()-routine can now be used for
+  both OFS and FFS.
+- The super block is now searched in the block that
+  was calculated and in the one following. This
+  should remedy the round-off error introduced by
+  the 1-k blocks that Linux uses.
+- Minor changes to adhere to the new VFS interface.
+- The number of used blocks is now also calculated
+  if the filesystem is mounted read-only.
+- Prefixed some constants with AFFS_ to avoid name
+  clashes.
+- Removed 'EXPERIMENTAL' status.
+
+Version 3.1
+-----------
+
+- Fixed a nasty bug which didn't allow read-only
+  mounts.
+- Allow dir-cache filesystems to be mounted
+  read only.
+- OFS support.
+- Several other changes I just cannot remember
+  any more.
+
+Version 3.0
+-----------
+
+- Almost complete rewrite for the new VFS
+  interface in Linux 1.3.
+- Write support.
+- Support for hard and symbolic links.
+- Lots of things I remeber even less ...
+
+Version 2.0
+-----------
+
+- Fixed a few things to get it compiled.
+- Automatic root block calculation.
+- Partition checker for genhd.c
+
+========================================
+
+Let's just call Ray Burr's original affs
+'Version 1.0'.
diff -u --recursive --new-file v2.1.36/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v2.1.36/linux/fs/affs/amigaffs.c	Sun May 19 05:22:19 1996
+++ linux/fs/affs/amigaffs.c	Mon May 12 10:35:42 1997
@@ -5,8 +5,10 @@
  *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
+ *  Please send bug reports to: hjw@zvw.de
  */
 
+#include <stdarg.h>
 #include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
@@ -17,6 +19,8 @@
 
 extern struct timezone sys_tz;
 
+static char ErrorBuffer[256];
+
 /*
  * Functions for accessing Amiga-FFS structures.
  *
@@ -28,7 +32,7 @@
    0 is returned.  Otherwise, the key number in the next used hash slot
    is returned. */
 
-int
+static int
 affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
 {
 	struct dir_front *dir_front = dir_data;
@@ -54,24 +58,23 @@
 	file_end = GET_END_PTR(struct file_end, fh_data, bsize);
 	if (file_end->file_name[0] == 0
 	    || file_end->file_name[0] > 30) {
-		printk ("affs_get_file_name: OOPS! bad filename\n");
-		printk ("  file_end->file_name[0] = %d\n",
+		printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n",
 			file_end->file_name[0]);
 		*name = "***BAD_FILE***";
 		return 14;
         }
-	*name = (char *) &file_end->file_name[1];
+	*name = (char *)&file_end->file_name[1];
         return file_end->file_name[0];
 }
 
 /* Find the predecessor in the hash chain */
 
 int
-affs_fix_hash_pred(struct inode *startino, int startoffset, int key, int newkey)
+affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey)
 {
 	struct buffer_head	*bh = NULL;
-	int			 nextkey;
-	int			 ptype, stype;
+	s32			 nextkey;
+	s32			 ptype, stype;
 	int			 retval;
 
 	nextkey = startino->i_ino;
@@ -87,14 +90,14 @@
 		    || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
 					    stype != ST_LINKFILE && stype != ST_LINKDIR &&
 					    stype != ST_ROOT && stype != ST_SOFTLINK)) {
-			printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n",
-			       ptype,stype);
+			affs_error(startino->i_sb,"affs_fix_hash_pred",
+				"Bad block in link chain (ptype=%d, stype=%d)",ptype,stype);
 			affs_brelse(bh);
 			break;
 		}
-		nextkey = htonl(((__u32 *)bh->b_data)[startoffset]);
+		nextkey = htonl(((s32 *)bh->b_data)[startoffset]);
 		if (nextkey == key) {
-			((__u32 *)bh->b_data)[startoffset] = newkey;
+			((s32 *)bh->b_data)[startoffset] = newkey;
 			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
 			mark_buffer_dirty(bh,1);
 			affs_brelse(bh);
@@ -112,13 +115,13 @@
 /* Remove inode from link chain */
 
 int
-affs_fix_link_pred(struct inode *startino, int key, int newkey)
+affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey)
 {
 	struct buffer_head	*bh = NULL;
-	int			 nextkey;
+	s32			 nextkey;
 	int			 offset;
-	int			 etype = 0;
-	int			 ptype, stype;
+	s32			 etype = 0;
+	s32			 ptype, stype;
 	int			 retval;
 
 	offset  = AFFS_I2BSIZE(startino) / 4 - 10;
@@ -150,7 +153,7 @@
 			retval = -EPERM;
 			break;
 		}
-		nextkey = htonl(((__u32 *)bh->b_data)[offset]);
+		nextkey = htonl(((s32 *)bh->b_data)[offset]);
 		if (nextkey == key) {
 			FILE_END(bh->b_data,startino)->link_chain = newkey;
 			affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
@@ -172,17 +175,17 @@
    (which lets us calculate the block size).
    Returns non-zero if the block is not consistent. */
 
-__u32
-affs_checksum_block(int bsize, void *data, int *ptype, int *stype)
+u32
+affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
 {
-	__u32	 sum;
-	__u32	*p;
+	u32	 sum;
+	u32	*p;
 
 	bsize /= 4;
 	if (ptype)
-		*ptype = htonl(((__s32 *)data)[0]);
+		*ptype = htonl(((s32 *)data)[0]);
 	if (stype)
-		*stype = htonl(((__s32 *)data)[bsize - 1]);
+		*stype = htonl(((s32 *)data)[bsize - 1]);
 
 	sum    = 0;
 	p      = data;
@@ -194,20 +197,20 @@
 void
 affs_fix_checksum(int bsize, void *data, int cspos)
 {
-	__u32	 ocs;
-	__u32	 cs;
+	u32	 ocs;
+	u32	 cs;
 
 	cs   = affs_checksum_block(bsize,data,NULL,NULL);
-	ocs  = htonl (((__u32 *)data)[cspos]);
+	ocs  = htonl (((u32 *)data)[cspos]);
 	ocs -= cs;
-	((__u32 *)data)[cspos] = htonl(ocs);
+	((u32 *)data)[cspos] = htonl(ocs);
 }
 
 void
-secs_to_datestamp(int secs, struct DateStamp *ds)
+secs_to_datestamp(time_t secs, struct DateStamp *ds)
 {
-	__u32	 days;
-	__u32	 minute;
+	u32	 days;
+	u32	 minute;
 
 	secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
 	if (secs < 0)
@@ -223,7 +226,7 @@
 }
 
 int
-prot_to_mode(__u32 prot)
+prot_to_mode(u32 prot)
 {
 	int	 mode = 0;
 
@@ -249,10 +252,10 @@
 	return mode;
 }
 
-unsigned int
+u32
 mode_to_prot(int mode)
 {
-	unsigned int	 prot = 0;
+	u32	 prot = 0;
 
 	if (mode & S_IXUSR)
 		prot |= FIBF_SCRIPT;
@@ -270,4 +273,33 @@
 		prot |= FIBF_OTR_WRITE;
 	
 	return prot;
+}
+
+void
+affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
+{
+	va_list	 args;
+
+	va_start(args,fmt);
+	vsprintf(ErrorBuffer,fmt,args);
+	va_end(args);
+
+	printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+		function,ErrorBuffer);
+	if (!(sb->s_flags & MS_RDONLY))
+		printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
+	sb->s_flags |= MS_RDONLY;
+}
+
+void
+affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
+{
+	va_list	 args;
+
+	va_start(args,fmt);
+	vsprintf(ErrorBuffer,fmt,args);
+	va_end(args);
+
+	printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+		function,ErrorBuffer);
 }
diff -u --recursive --new-file v2.1.36/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- v2.1.36/linux/fs/affs/bitmap.c	Sun Nov 10 04:05:48 1996
+++ linux/fs/affs/bitmap.c	Mon May 12 17:39:50 1997
@@ -3,7 +3,6 @@
  *
  *  (c) 1996 Hans-Joachim Widmaier
  *
- *
  *  bitmap.c contains the code that handles all bitmap related stuff -
  *  block allocation, deallocation, calculation of free space.
  */
@@ -54,7 +53,7 @@
 }
 
 void
-affs_free_block(struct super_block *sb, int block)
+affs_free_block(struct super_block *sb, s32 block)
 {
 	int			 bmap;
 	int			 bit;
@@ -70,7 +69,7 @@
 	zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024;
 	bm      = &sb->u.affs_sb.s_bitmap[bmap];
 	if (bmap >= sb->u.affs_sb.s_bm_count) {
-		printk("AFFS: free_block(): block %d outside partition.\n",block);
+		affs_error(sb,"affs_free_block","Block %d outside partition",block);
 		return;
 	}
 	blk = 0;
@@ -83,15 +82,16 @@
 		if (!bm->bm_bh) {
 			bm->bm_count--;
 			unlock_super(sb);
-			printk("AFFS: free_block(): Cannot read bitmap block %d\n",bm->bm_key);
+			affs_error(sb,"affs_free_block","Cannot read bitmap block %d",bm->bm_key);
 			return;
 		}
 	}
-	if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
-		printk("AFFS: free_block(): block %d is already free.\n",block);
+	if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
+		affs_warning(sb,"affs_free_block","Trying to free block %d which is already free",
+				block);
 	else {
 		sb->u.affs_sb.s_alloc[zone_no].az_free++;
-		((__u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((__u32 *)bm->bm_bh->b_data)[0]) - blk);
+		((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk);
 		mark_buffer_dirty(bm->bm_bh,1);
 		sb->s_dirt = 1;
 	}
@@ -102,15 +102,15 @@
 	unlock_super(sb);
 }
 
-static int
+static s32
 affs_balloc(struct inode *inode, int zone_no)
 {
-	__u32			 w;
-	__u32			*bm;
+	u32			 w;
+	u32			*bm;
 	int			 fb;
 	int			 i;
 	int			 fwb;
-	int			 block;
+	s32			 block;
 	struct affs_zone	*zone;
 	struct affs_alloc_zone	*az;
 	struct super_block	*sb;
@@ -124,7 +124,7 @@
 	pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
 
 	az = &sb->u.affs_sb.s_alloc[zone->z_az_no];
-	bm = (__u32 *)zone->z_bm->bm_bh->b_data;
+	bm = (u32 *)zone->z_bm->bm_bh->b_data;
 repeat:
 	for (i = zone->z_start; i < zone->z_end; i++) {
 		if (bm[i])
@@ -138,9 +138,9 @@
 	zone->z_start = i;
 	w   = ~htonl(bm[i]);
 	fb  = find_first_zero_bit(&w,32);
-	if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+	if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
 		unlock_super(sb);
-		printk("AFFS: balloc(): empty block disappeared somehow\n");
+		affs_warning(sb,"balloc","Empty block disappeared somehow");
 		goto repeat;
 	}
 	block = fwb + fb;
@@ -153,8 +153,8 @@
 			fb = find_next_zero_bit(&w,32,fb);
 			if (fb > 31)
 				break;
-			if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
-				printk("AFFS: balloc(): empty block disappeared\n");
+			if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+				affs_warning(sb,"balloc","Empty block disappeared somehow");
 				break;
 			}
 			inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
@@ -204,7 +204,7 @@
 		if (az->az_count)
 			az->az_count--;
 		else
-			printk("AFFS: find_new_zone(): az_count=0, but bm used\n");
+			affs_error(sb,"find_new_zone","az_count=0, but bm used");
 
 	}
 	while (1) {
@@ -247,7 +247,7 @@
 		bm->bm_count--;
 		az->az_count--;
 		unlock_super(sb);
-		printk("AFFS: find_new_zone(): Cannot read bitmap\n");
+		affs_error(sb,"find_new_zone","Cannot read bitmap");
 		return 0;
 	}
 	zone->z_bm    = bm;
@@ -261,16 +261,16 @@
 	return az->az_free;
 }
 
-int
+s32
 affs_new_header(struct inode *inode)
 {
-	int			 block;
+	s32			 block;
 	struct buffer_head	*bh;
 
 	pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
 
 	if (!(block = affs_balloc(inode,0))) {
-		while(affs_find_new_zone(inode->i_sb,0)) {
+		while (affs_find_new_zone(inode->i_sb,0)) {
 			if ((block = affs_balloc(inode,0)))
 				goto init_block;
 			schedule();
@@ -279,7 +279,7 @@
 	}
 init_block:
 	if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
-		printk("AFFS: balloc(): cannot read block %d\n",block);
+		affs_error(inode->i_sb,"new_header","Cannot read block %d",block);
 		return 0;
 	}
 	memset(bh->b_data,0,AFFS_I2BSIZE(inode));
@@ -290,7 +290,7 @@
 	return block;
 }
 
-int
+s32
 affs_new_data(struct inode *inode)
 {
 	int			 empty, old;
@@ -299,7 +299,7 @@
 	struct super_block	*sb;
 	struct buffer_head	*bh;
 	int			 i = 0;
-	int			 block;
+	s32			 block;
 
 	pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
 
@@ -345,7 +345,7 @@
 found:
 	zone = &sb->u.affs_sb.s_zones[i];
 	if (!(block = affs_balloc(inode,i))) {		/* No data zones left */
-		while(affs_find_new_zone(sb,i)) {
+		while (affs_find_new_zone(sb,i)) {
 			if ((block = affs_balloc(inode,i)))
 				goto init_block;
 			schedule();
@@ -357,7 +357,7 @@
 
 init_block:
 	if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
-		printk("AFFS: balloc(): cannot read block %u\n",block);
+		affs_error(inode->i_sb,"new_data","Cannot read block %d",block);
 		return 0;
 	}
 	memset(bh->b_data,0,sb->s_blocksize);
diff -u --recursive --new-file v2.1.36/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v2.1.36/linux/fs/affs/dir.c	Sun Jan 26 02:07:24 1997
+++ linux/fs/affs/dir.c	Mon May 12 10:35:42 1997
@@ -64,7 +64,7 @@
 };
 
 static long
-affs_dir_read(struct inode * inode, struct file * filp, char * buf, unsigned long count)
+affs_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
 {
 	return -EISDIR;
 }
@@ -73,19 +73,18 @@
 affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
 {
 	int			 j, namelen;
-	int			 i;
+	s32			 i;
 	int			 hash_pos;
 	int			 chain_pos;
 	unsigned long		 ino;
 	unsigned long		 old;
-	int stored;
-	char *name;
-	struct buffer_head *dir_bh;
-	struct buffer_head *fh_bh;
-	struct inode	   *dir;
+	int			 stored;
+	char			 *name;
+	struct buffer_head	 *dir_bh;
+	struct buffer_head	 *fh_bh;
+	struct inode		 *dir;
 
 	pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
-	
 
 	if (!inode || !S_ISDIR(inode->i_mode))
 		return -EBADF;
@@ -122,7 +121,7 @@
 	chain_pos = (filp->f_pos - 2) & 0xffff;
 	hash_pos  = (filp->f_pos - 2) >> 16;
 	if (chain_pos == 0xffff) {
-		printk("AFFS: more than 65535 entries in chain\n");
+		affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
 		chain_pos = 0;
 		hash_pos++;
 		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
@@ -143,15 +142,15 @@
 		 * we can jump directly to where we left off.
 		 */
 		if (filp->private_data && filp->f_version == dir->i_version) {
-			i = (int)filp->private_data;
+			i = (s32)filp->private_data;
 			j = 0;
 			pr_debug("AFFS: readdir() left off=%d\n",i);
 		}
 		filp->f_version = dir->i_version;
-		pr_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+		pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
 		while (i) {
 			if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
-				printk("AFFS: readdir: Can't get block %d\n",i);
+				affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
 				goto readdir_done;
 			}
 			ino = i;
@@ -164,7 +163,7 @@
 		}
 		if (fh_bh) {
 			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
-			pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",
+			pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n",
 				 namelen,name,ino,i);
 			filp->private_data = (void *)ino;
 			if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
diff -u --recursive --new-file v2.1.36/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.1.36/linux/fs/affs/file.c	Fri Apr  4 08:52:23 1997
+++ linux/fs/affs/file.c	Mon May 12 10:35:42 1997
@@ -35,6 +35,8 @@
 #error PAGE_SIZE must be at least 4096
 #endif
 
+static int affs_bmap(struct inode *inode, int block);
+static struct buffer_head * affs_getblock(struct inode *inode, s32 block);
 static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf,
 			       unsigned long count);
 static long affs_file_write(struct inode *inode, struct file *filp, const char *buf,
@@ -200,7 +202,7 @@
 	return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);
 }
 
-static int __inline__
+static s32 __inline__
 calc_key(struct inode *inode, int *ext)
 {
 	int		  index;
@@ -226,28 +228,30 @@
 	return inode->u.affs_i.i_ec->ec[index];
 }
 
-int
+static int
 affs_bmap(struct inode *inode, int block)
 {
 	struct buffer_head	*bh;
-	int			 ext, key, nkey;
-	int			 ptype, stype;
+	s32			 key, nkey;
+	s32			 ptype, stype;
+	int			 ext;
 	int			 index;
 	int			 keycount;
 	struct key_cache	*kc;
 	struct key_cache	*tkc;
 	struct timeval		 tv;
-	__s32			*keyp;
+	s32			*keyp;
 	int			 i;
 
 	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
 
 	if (block < 0) {
-		printk("affs_bmap: block < 0\n");
+		affs_error(inode->i_sb,"bmap","Block < 0");
 		return 0;
 	}
 	if (!inode->u.affs_i.i_ec) {
-		printk("affs_bmap(): No ext_cache!?\n");
+		affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)",
+			inode->i_ino);
 		return 0;
 	}
 
@@ -334,14 +338,14 @@
 	return key;
 }
 
-struct buffer_head *
-affs_getblock(struct inode *inode, int block)
+static struct buffer_head *
+affs_getblock(struct inode *inode, s32 block)
 {
 	struct buffer_head	*bh;
 	struct buffer_head	*ebh;
 	struct buffer_head	*pbh;
 	struct key_cache	*kc;
-	int			 key, nkey;
+	s32			 key, nkey;
 	int			 ext;
 	int			 cf, j, pt;
 	int			 index;
@@ -372,7 +376,7 @@
 			return NULL;
 		if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) ||
 		    cf != pt || j != ST_FILE) {
-		    	printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+		    	affs_error(inode->i_sb,"getblock","Inode %d is not a valid %s",key,
 			       pt == T_SHORT ? "file header" : "extension block");
 			affs_brelse(bh);
 			return NULL;
@@ -387,7 +391,8 @@
 				else
 					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
 				if (!pbh) {
-					printk("AFFS: getblock(): cannot get last block in file\n");
+					affs_error(inode->i_sb,"getblock",
+						"Cannot get last block in file");
 					break;
 				}
 			}
@@ -397,7 +402,7 @@
 			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_warning(inode->i_sb,"getblock","Block already allocated");
 				affs_free_block(inode->i_sb,nkey);
 				j++;
 				continue;
@@ -407,7 +412,8 @@
 			if (ofs) {
 				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
 				if (!ebh) {
-					printk("AFFS: getblock(): cannot get block %d\n",nkey);
+					affs_error(inode->i_sb,"getblock",
+						   "Cannot get block %d",nkey);
 					affs_free_block(inode->i_sb,nkey);
 					AFFS_BLOCK(bh->b_data,inode,j) = 0;
 					break;
@@ -492,10 +498,6 @@
 	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.
- */
-
 static long
 affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count)
 {
@@ -508,12 +510,12 @@
 	pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
 
 	if (!inode) {
-		printk("affs_file_read: inode = NULL\n");
+		affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
 		return -EINVAL;
 	}
 	blocksize = AFFS_I2BSIZE(inode) - 24;
 	if (!(S_ISREG(inode->i_mode))) {
-		pr_debug("affs_file_read: mode = %07o\n",inode->i_mode);
+		pr_debug("affs_file_read: mode = %07o",inode->i_mode);
 		return -EINVAL;
 	}
 	if (filp->f_pos >= inode->i_size || count <= 0)
@@ -524,10 +526,10 @@
 		left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
 		if (!left)
 			break;
-		sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize);
+		sector = affs_bmap(inode,(u32)filp->f_pos / blocksize);
 		if (!sector)
 			break;
-		offset = (__u32)filp->f_pos % blocksize;
+		offset = (u32)filp->f_pos % blocksize;
 		bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
 		if (!bh)
 			break;
@@ -554,25 +556,31 @@
 	struct inode		*ino;
 	char			*p;
 
+	/* Not that I wanted to be POSIX compliant ... */
+	if (!count)
+		return 0;
 	pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
 		(unsigned long)filp->f_pos,count);
 
 	ino = NULL;
 	if (!inode) {
-		printk("AFFS: file_write(): inode=NULL\n");
+		affs_error(inode->i_sb,"file_write","Inode = NULL");
 		return -EINVAL;
 	}
 	if (inode->u.affs_i.i_original) {
 		ino = iget(inode->i_sb,inode->u.affs_i.i_original);
 		if (!ino) {
-			printk("AFFS: could not follow link from inode %lu to %d\n",
-			       inode->i_ino,inode->u.affs_i.i_original);
+			affs_error(inode->i_sb,"file_write",
+				   "Could not follow link from inode %lu to %d",
+			           inode->i_ino,inode->u.affs_i.i_original);
 			return -EINVAL;
 		}
 		inode = ino;
 	}
 	if (!S_ISREG(inode->i_mode)) {
-		printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+		affs_error(inode->i_sb,"file_write",
+			   "Trying to write to non-regular file (mode=%07o)",
+			   inode->i_mode);
 		iput(inode);
 		return -EINVAL;
 	}
@@ -636,22 +644,27 @@
 	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
 		(unsigned long)filp->f_pos,count);
 
+	if (!count)
+		return 0;
 	if (!inode) {
-		printk("AFFS: file_write_ofs(): inode=NULL\n");
+		affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
 		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: could not follow link from inode %lu to %d\n",
-			       inode->i_ino,inode->u.affs_i.i_original);
+			affs_error(inode->i_sb,"file_write_ofs",
+				   "Could not follow link from inode %lu to %d",
+			           inode->i_ino,inode->u.affs_i.i_original);
 			return -EINVAL;
 		}
 		inode = ino;
 	}
 	if (!S_ISREG(inode->i_mode)) {
-		printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode);
+		affs_error(inode->i_sb,"file_write_ofs",
+			   "Trying to write to non-regular file (mode=%07o)",
+			   inode->i_mode);
 		iput(inode);
 		return -EINVAL;
 	}
@@ -714,10 +727,10 @@
 	struct affs_zone	*zone;
 	int	 first;
 	int	 block;
-	int	 key;
-	int	*keyp;
-	int	 ekey;
-	int	 ptype, stype;
+	s32	 key;
+	s32	*keyp;
+	s32	 ekey;
+	s32	 ptype, stype;
 	int	 freethis;
 	int	 blocksize;
 	int	 rem;
@@ -729,8 +742,8 @@
 	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",
-			       inode->i_ino,inode->u.affs_i.i_original);
+			affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d",
+			           inode->i_ino,inode->u.affs_i.i_original);
 			return;
 		}
 		inode = ino;
@@ -754,7 +767,7 @@
 			unlock_super(inode->i_sb);
 		}
 		if (!bh) {
-			printk("AFFS: truncate(): Cannot extend file\n");
+			affs_error(inode->i_sb,"truncate","Cannot extend file");
 			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;
@@ -771,7 +784,7 @@
 
 	while (ekey) {
 		if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
-			printk("AFFS: truncate(): Can't read block %d\n",ekey);
+			affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
 			break;
 		}
 		ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
@@ -783,14 +796,14 @@
 			break;
 		}
 		if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
-			printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
-			        ptype,stype);
+			affs_error(inode->i_sb,"truncate","Bad block (ptype=%d, stype=%d)",
+			           ptype,stype);
 			affs_brelse(bh);
 			break;
 		}
 		/* Do not throw away file header */
 		freethis = first == 0 && ekey != inode->i_ino;
-		for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+		for (block = first; block < AFFS_I2HSIZE(inode); block++) {
 			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
 			key  = htonl(*keyp);
 			if (key) {
@@ -853,7 +866,7 @@
 affs_open_file(struct inode *inode, struct file *filp)
 {
 	int	 error;
-	int	 key;
+	u32	 key;
 	int	 i;
 
 	pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
@@ -864,7 +877,7 @@
 	if (!inode->u.affs_i.i_ec) {
 		inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
 		if (!inode->u.affs_i.i_ec) {
-			printk("AFFS: cache allocation failed\n");
+			affs_error(inode->i_sb,"open_file","Cache allocation failed");
 			error = ENOMEM;
 		} else {
 			/* We only have to initialize non-zero values.
diff -u --recursive --new-file v2.1.36/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.1.36/linux/fs/affs/inode.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/affs/inode.c	Mon May 12 10:35:42 1997
@@ -30,12 +30,26 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+/* AmigaOS allows file names with up to 30 characters length.
+ * Names longer than that will be silently truncated. If you
+ * want to disallow this, comment out the following #define.
+ * Creating filesystem objects with longer names will then
+ * result in an error (ENAMETOOLONG).
+ */
+/*#define NO_TRUNCATE */
+
 extern int *blk_size[];
 extern struct timezone sys_tz;
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
 
-void
+static int affs_notify_change(struct inode *inode, struct iattr *attr);
+static void affs_put_inode(struct inode *inode);
+static void affs_read_inode(struct inode *inode);
+static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void affs_write_inode(struct inode *inode);
+
+static void
 affs_put_super(struct super_block *sb)
 {
 	int	 i;
@@ -110,13 +124,13 @@
 	NULL			/* remount */
 };
 
-int
+unsigned long
 affs_parent_ino(struct inode *dir)
 {
 	int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
 
 	if (!S_ISDIR (dir->i_mode)) {
-		printk ("affs_parent_ino: argument is not a directory\n");
+		affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory");
 		return root_ino;
 	}
 	if (dir->i_ino == root_ino)
@@ -125,7 +139,7 @@
 }
 
 static int
-parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root,
+parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
 		int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
 {
 	char	*this_char, *value;
@@ -150,14 +164,14 @@
 			*value++ = 0;
 		if (!strcmp(this_char,"protect")) {
 			if (value) {
-				printk("AFFS: option protect does not take an argument\n");
+				printk("AFFS: Option protect does not take an argument\n");
 				return 0;
 			}
 			*mount_opts |= SF_IMMUTABLE;
 		}
 		else if (!strcmp(this_char,"verbose")) {
 			if (value) {
-				printk("AFFS: option verbose does not take an argument\n");
+				printk("AFFS: Option verbose does not take an argument\n");
 				return 0;
 			}
 			*mount_opts |= SF_VERBOSE;
@@ -166,7 +180,7 @@
 			if (!value)
 				*uid = current->uid;
 			else if (!*value) {
-				printk("AFFS: argument for uid option missing\n");
+				printk("AFFS: Argument for uid option missing\n");
 				return 0;
 			} else {
 				*uid = simple_strtoul(value,&value,0);
@@ -180,7 +194,7 @@
 			if (!value)
 				*gid = current->gid;
 			else if (!*value) {
-				printk("AFFS: argument for gid option missing\n");
+				printk("AFFS: Argument for gid option missing\n");
 				return 0;
 			} else {
 				*gid = simple_strtoul(value,&value,0);
@@ -248,7 +262,7 @@
 				return 0;
 			if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
 			    && *blocksize != 4096) {
-				printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n");
+				printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
 				return 0;
 			}
 		}
@@ -270,21 +284,21 @@
  * hopefully have the guts to do so. Until then: sorry for the mess.
  */
 
-struct super_block *
+static struct super_block *
 affs_read_super(struct super_block *s,void *data, int silent)
 {
 	struct buffer_head	*bh = NULL;
 	struct buffer_head	*bb;
 	kdev_t			 dev = s->s_dev;
-	int			 root_block;
+	s32			 root_block;
 	int			 size;
-	__u32			 chksum;
-	__u32			*bm;
-	int			 ptype, stype;
+	u32			 chksum;
+	u32			*bm;
+	s32			 ptype, stype;
 	int			 mapidx;
 	int			 num_bm;
 	int			 i, j;
-	int			 key;
+	s32			 key;
 	int			 blocksize;
 	uid_t			 uid;
 	gid_t			 gid;
@@ -300,7 +314,7 @@
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
 	    &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
 		s->s_dev = 0;
-		printk("AFFS: error parsing options.\n");
+		printk(KERN_ERR "AFFS: Error parsing options\n");
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
@@ -324,13 +338,13 @@
 	if (size == 0) {
 		s->s_dev = 0;
 		unlock_super(s);
-		printk("affs_read_super: could not determine device size\n");
+		printk(KERN_ERR "AFFS: Could not determine device size\n");
 		goto out;
 	}
 	s->u.affs_sb.s_partition_size = size;
 	s->u.affs_sb.s_reserved       = reserved;
 
-	/* Try to find root block. Its location may depend on the block size. */
+	/* Try to find root block. Its location depends on the block size. */
 
 	s->u.affs_sb.s_hashsize = 0;
 	if (blocksize > 0) {
@@ -358,12 +372,12 @@
 		 * block behind the calculated one. So we check this one, too.
 		 */
 		for (num_bm = 0; num_bm < 2; num_bm++) {
-			pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %d, "
+			pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, "
 				 "size=%d blocks, %d reserved\n",kdevname(dev),blocksize,
 				 s->u.affs_sb.s_root_block + num_bm,size,reserved);
 			bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize);
 			if (!bh) {
-				printk("AFFS: unable to read root block\n");
+				printk(KERN_ERR "AFFS: Cannot read root block\n");
 				goto out;
 			}
 			if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
@@ -383,7 +397,8 @@
 	if (!key) {
 		affs_brelse(bh);
 		if (!silent)
-			printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev));
+			printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n",
+				kdevname(dev));
 		goto out;
 	}
 	root_block = s->u.affs_sb.s_root_block;
@@ -396,7 +411,7 @@
 	/* Find out which kind of FS we have */
 	bb = affs_bread(dev,0,s->s_blocksize);
 	if (bb) {
-		chksum = htonl(*(__u32 *)bb->b_data);
+		chksum = htonl(*(u32 *)bb->b_data);
 
 		/* Dircache filesystems are compatible with non-dircache ones
 		 * when reading. As long as they aren't supported, writing is
@@ -404,7 +419,8 @@
 		 */
 		if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
 		     || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
-			printk("AFFS: Dircache FS - mounting %s read only.\n",kdevname(dev));
+			printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
+				kdevname(dev));
 			s->s_flags |= MS_RDONLY;
 		}
 		switch (chksum) {
@@ -436,22 +452,22 @@
 				s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
 				break;
 			default:
-				printk("AFFS: Unknown filesystem on device %s: %08X\n",
-				       kdevname(dev),chksum);
+				printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
+					kdevname(dev),chksum);
 				affs_brelse(bb);
 				goto out;
 		}
 		affs_brelse(bb);
 	} else {
-		printk("AFFS: Can't get boot block.\n");
+		printk(KERN_ERR "AFFS: Cannot read boot block\n");
 		goto out;
 	}
 	if (mount_flags & SF_VERBOSE) {
 		chksum = ntohl(chksum);
-		printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-		       GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
-		       &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
-		       (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+		printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
+			GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
+			&GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+			(char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
 	}
 
 	s->s_magic  = AFFS_SUPER_MAGIC;
@@ -459,7 +475,7 @@
 
 	/* Keep super block in cache */
 	if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
-		printk("AFFS: Can't read root block a second time\n");
+		printk(KERN_ERR "AFFS: Cannot read root block\n");
 		goto out;
 	}
 
@@ -473,7 +489,7 @@
 		 MAX_ZONES * sizeof(struct affs_zone);
 	pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
 	if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
-		printk("AFFS: Not enough memory.\n");
+		printk(KERN_ERR "AFFS: Not enough memory\n");
 		goto out;
 	}
 	memset(s->u.affs_sb.s_bitmap,0,ptype);
@@ -486,7 +502,8 @@
 
 	if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
 		if (!(s->s_flags & MS_RDONLY)) {
-			printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev));
+			printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
+				kdevname(dev));
 			s->s_flags |= MS_RDONLY;
 		}
 		affs_brelse(bh);
@@ -504,17 +521,17 @@
 	offset = s->u.affs_sb.s_reserved;
 	az_no  = 0;
 	while (bh) {
-		bm = (__u32 *)bh->b_data;
+		bm = (u32 *)bh->b_data;
 		for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
 			if (mapidx >= num_bm) {
-				printk("AFFS: Not enough bitmap space!?\n");
+				printk(KERN_ERR "AFFS: Not enough bitmap space!?\n");
 				goto out;
 			}
 			bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
 			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 - "
+					printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - "
 					       "mounting %s read only.\n",mapidx,htonl(bm[i]),
 						kdevname(dev));
 					s->s_flags |= MS_RDONLY;
@@ -525,7 +542,7 @@
 					key   = size & 0x1F;		/* used bits */
 					if (key) {
 						chksum = ntohl(0x7FFFFFFF >> (31 - key));
-						((__u32 *)bb->b_data)[ptype] &= chksum;
+						((u32 *)bb->b_data)[ptype] &= chksum;
 						affs_fix_checksum(s->s_blocksize,bb->b_data,0);
 						mark_buffer_dirty(bb,1);
 					}
@@ -551,7 +568,7 @@
 				}
 				affs_brelse(bb);
 			} else {
-				printk("AFFS: Can't read bitmap.\n");
+				printk(KERN_ERR "AFFS: Cannot read bitmap\n");
 				goto out;
 			}
 		}
@@ -561,14 +578,14 @@
 		affs_brelse(bh);
 		if (key) {
 			if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
-				printk("AFFS: Can't read bitmap extension.\n");
+				printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
 				goto out;
 			}
 		} else
 			bh = NULL;
 	}
 	if (mapidx != num_bm) {
-		printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
+		printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
 		goto out;
 	}
 nobitmap:
@@ -584,7 +601,7 @@
 
 	if (!(s->s_mounted)) {
 		s->s_dev = 0;
-		printk("AFFS: get root inode failed\n");
+		printk(KERN_ERR "AFFS: get root inode failed\n");
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
@@ -615,7 +632,7 @@
 	return NULL;
 }
 
-void
+static void
 affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	int		 free;
@@ -635,15 +652,15 @@
 	copy_to_user(buf,&tmp,bufsiz);
 }
 
-void
+static void
 affs_read_inode(struct inode *inode)
 {
 	struct buffer_head	*bh, *lbh;
 	struct file_front	*file_front;
 	struct file_end		*file_end;
-	int			 block;
+	s32			 block;
 	unsigned long		 prot;
-	int			 ptype, stype;
+	s32			 ptype, stype;
 	unsigned short		 id;
 
 	pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
@@ -651,12 +668,12 @@
 	lbh   = NULL;
 	block = inode->i_ino;
 	if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
-		printk("AFFS: unable to read i-node block %d\n",block);
+		affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
 		return;
 	}
 	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);
+		affs_error(inode->i_sb,"read_inode",
+			   "Checksum or type (ptype=%d) error on inode %d",ptype,block);
 		affs_brelse(bh);
 		return;
 	}
@@ -735,7 +752,8 @@
 			if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original,
 			                  AFFS_I2BSIZE(inode)))) {
 				affs_brelse(bh);
-				printk("AFFS: unable to read i-node block %ld\n",inode->i_ino);
+				affs_error(inode->i_sb,"read_inode","Cannot read block %lu",
+					   inode->i_ino);
 				return;
 			}
 			file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode));
@@ -776,12 +794,13 @@
 		inode->i_op = &affs_symlink_inode_operations;
 }
 
-void
+static void
 affs_write_inode(struct inode *inode)
 {
-	struct buffer_head *bh;
-	struct file_end	   *file_end;
-	short		    uid, gid;
+	struct buffer_head	*bh;
+	struct file_end		*file_end;
+	uid_t			 uid;
+	gid_t			 gid;
 
 	pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
 
@@ -789,8 +808,7 @@
 	if (!inode->i_nlink)
 		return;
 	if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
-		printk("AFFS: Unable to read block of inode %ld on %s\n",
-		       inode->i_ino,kdevname(inode->i_dev));
+		affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino);
 		return;
 	}
 	file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
@@ -820,7 +838,7 @@
 	brelse(bh);
 }
 
-int
+static int
 affs_notify_change(struct inode *inode, struct iattr *attr)
 {
 	int error;
@@ -848,7 +866,7 @@
 	return 0;
 }
 
-void
+static void
 affs_put_inode(struct inode *inode)
 {
 	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
@@ -867,7 +885,7 @@
 {
 	struct inode		*inode;
 	struct super_block	*sb;
-	int			 block;
+	s32			 block;
 
 	if (!dir || !(inode = get_empty_inode()))
 		return NULL;
@@ -918,7 +936,10 @@
 	struct buffer_head	*dir_bh;
 	struct buffer_head	*inode_bh;
 	struct buffer_head	*link_bh;
-	int			 hash;
+	struct buffer_head	*ibh;
+	int			 retval;
+	int			 i;
+	s32			 next;
 
 	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino,
 		 len,name,type);
@@ -926,34 +947,60 @@
 	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);
-		return -ENOSPC;
-	}
+	retval       = -EIO;
+	if (!dir_bh || !inode_bh)
+		goto addentry_done;
 	if (link) {
 		link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
-		if (!link_bh) {
-			affs_brelse(dir_bh);
-			affs_brelse(inode_bh);
-			return -EINVAL;
-		}
+		if (!link_bh)
+			goto addentry_done;
 	}
 	((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT);
 	((struct dir_front *)inode_bh->b_data)->own_key      = ntohl(inode->i_ino);
 
-	if (len > 30)		/* truncate name quietly */
+	retval = -ENAMETOOLONG;
+	if (len > 30)
+#ifdef NO_TRUNCATE
+		goto addentry_done;
+#else
 		len = 30;
+#endif
+
+	/* Check if name is valid */
+	retval = -EINVAL;
+	for (i = 0; i < len; i++) {
+		if (name[i] < ' ' || name[i] == ':'
+		    || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0))
+			goto addentry_done;
+	}
+	retval = 0;
 	DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
 	strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
 	DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type);
 	DIR_END(inode_bh->b_data,inode)->parent         = ntohl(dir->i_ino);
-	hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir));
+
+	i    = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6;
+	next = dir->i_ino;
+
+	/* Alas, we have to search the insertion point with a locked sb */
 
 	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] = ntohl(inode->i_ino);
+	while (1) {
+		if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir))))
+			goto addentry_done;
+		next = htonl(((s32 *)ibh->b_data)[i]);
+		if (!next || next > inode->i_ino)
+			break;
+		i = AFFS_I2BSIZE(dir) / 4 - 4;
+		affs_brelse(ibh);
+	}
+
+	DIR_END(inode_bh->b_data,inode)->hash_chain = next;
+	((s32 *)ibh->b_data)[i]                     = ntohl(inode->i_ino);
+	affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5);
+	mark_buffer_dirty(ibh,1);
+	affs_brelse(ibh);
+
 	if (link_bh) {
 		LINK_END(inode_bh->b_data,inode)->original   = ntohl(link->i_ino);
 		LINK_END(inode_bh->b_data,inode)->link_chain =
@@ -974,11 +1021,13 @@
 	inode->i_dirt  = 1;
 	mark_buffer_dirty(dir_bh,1);
 	mark_buffer_dirty(inode_bh,1);
+
+addentry_done:
 	affs_brelse(dir_bh);
 	affs_brelse(inode_bh);
 	affs_brelse(link_bh);
 
-	return 0;
+	return retval;
 }
 
 static struct file_system_type affs_fs_type = {
@@ -999,7 +1048,7 @@
 int
 init_module(void)
 {
-	return init_affs_fs();
+	return register_filesystem(&affs_fs_type);
 }
 
 void
diff -u --recursive --new-file v2.1.36/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.1.36/linux/fs/affs/namei.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/affs/namei.c	Mon May 12 10:35:42 1997
@@ -20,6 +20,8 @@
 
 #include <linux/errno.h>
 
+static int affs_fixup(struct buffer_head *bh, struct inode *inode);
+
 /* Simple toupper() for DOS\1 */
 
 static inline unsigned int
@@ -100,7 +102,7 @@
 {
 	struct buffer_head *bh;
 	int	 intl;
-	int	 key;
+	s32	 key;
 
 	pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
 
@@ -222,9 +224,7 @@
 	
 	pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
 
-
 	*result = NULL;
-
 	if (!dir || !dir->i_sb) {
 		iput(dir);
 		return -EINVAL;
@@ -472,7 +472,7 @@
 		iput(oldinode);
 		oldinode = iget(dir->i_sb,i);
 		if (!oldinode) {
-			printk("AFFS: link(): original does not exist.\n");
+			affs_error(oldinode->i_sb,"link","Cannot get original from link");
 			iput(dir);
 			return -ENOENT;
 		}
@@ -507,7 +507,7 @@
 }
 
 static int
-subdir(struct inode * new_inode, struct inode * old_inode)
+subdir(struct inode *new_inode, struct inode *old_inode)
 {
     int ino;
     int result;
@@ -650,11 +650,11 @@
 	return retval;
 }
 
-int
+static int
 affs_fixup(struct buffer_head *bh, struct inode *inode)
 {
-	int			 key, link_key;
-	int			 type;
+	s32			 key, link_key;
+	s32			 type;
 	struct buffer_head	*nbh;
 	struct inode		*ofinode;
 
@@ -663,7 +663,8 @@
 		key = htonl(LINK_END(bh->b_data,inode)->original);
 		LINK_END(bh->b_data,inode)->original = 0;
 		if (!key) {
-			printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
+			affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu",
+				   inode->i_ino);
 			return -ENOENT;
 		}
 		if (!(ofinode = iget(inode->i_sb,key)))
@@ -676,17 +677,18 @@
 		if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
 			/* Get first link, turn it to a file */
 			if (!(ofinode = iget(inode->i_sb,key))) {
-				printk("AFFS: fixup(): cannot read inode %u\n",key);
+				affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
 				return -ENOENT;
 			}
 			if (!ofinode->u.affs_i.i_hlink) {
-				printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
-					inode->i_ino,key);
+				affs_error(inode->i_sb,"fixup",
+					   "First link to %lu (%d) is not a link",
+					   inode->i_ino,key);
 				iput(ofinode);
 				return -ENOENT;
 			}
 			if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
-				printk("AFFS: fixup(): cannot read block %u\n",key);
+				affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
 				iput(ofinode);
 				return -ENOENT;
 			}
@@ -719,13 +721,14 @@
 					break;
 				if ((ofinode = iget(inode->i_sb,key))) {
 					if (!ofinode->u.affs_i.i_hlink)
-						printk("AFFS: fixup() inode %u in link chain is "
-						       "not a link\n",key);
+						affs_error(inode->i_sb,"fixup",
+							   "Inode %d in link chain is not a link",
+							   key);
 					ofinode->u.affs_i.i_original = link_key;
 					ofinode->i_dirt              = 1;
 					FILE_END(nbh->b_data,inode)->original = htonl(link_key);
 				} else
-					printk("AFFS: fixup(): cannot get inode %u\n",key);
+					affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
 			}
 			/* Turn old inode to a link */
 			inode->u.affs_i.i_hlink = 1;
@@ -735,7 +738,7 @@
 	} else if (type == ST_SOFTLINK) {
 		return 0;
 	} else {
-		printk("AFFS: fixup(): secondary type=%d\n",type);
+		affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type);
 		return -EBADF;
 	}
 }
diff -u --recursive --new-file v2.1.36/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v2.1.36/linux/fs/affs/symlink.c	Mon Oct 28 04:29:25 1996
+++ linux/fs/affs/symlink.c	Mon May 12 10:35:42 1997
@@ -82,7 +82,7 @@
 	i  = 0;
 	j  = 0;
 	if (!bh) {
-		printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+		affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino);
 		kfree(buffer);
 		iput(inode);
 		iput(dir);
@@ -138,7 +138,7 @@
 	i  = 0;
 	j  = 0;
 	if (!bh) {
-		printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+		affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino);
 		goto symlink_end;
 	}
 	lf = (struct slink_front *)bh->b_data;
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/Makefile linux/fs/autofs/Makefile
--- v2.1.36/linux/fs/autofs/Makefile	Fri Apr  4 08:52:24 1997
+++ linux/fs/autofs/Makefile	Mon May 12 10:35:42 1997
@@ -1,11 +1,7 @@
 #
 # Makefile for the linux autofs-filesystem routines.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
+# We can build this either out of the kernel tree or the autofs tools tree.
 #
 
 O_TARGET := autofs.o
@@ -13,4 +9,27 @@
 
 M_OBJS   := $(O_TARGET)
 
+ifdef TOPDIR
+#
+# Part of the kernel code
+#
 include $(TOPDIR)/Rules.make
+else
+#
+# Standalone (handy for development)
+#
+include ../Makefile.rules
+
+CFLAGS += -D__KERNEL__ -DMODULE $(KFLAGS) -I../include -I$(KINCLUDE) $(MODFLAGS)
+
+all: $(O_TARGET)
+
+$(O_TARGET): $(O_OBJS)
+	$(LD) -r -o $(O_TARGET) $(O_OBJS)
+
+install: $(O_TARGET)
+	install -c $(O_TARGET) /lib/modules/`uname -r`/fs
+
+clean:
+	rm -f *.o *.s
+endif
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.1.36/linux/fs/autofs/autofs_i.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/autofs/autofs_i.h	Tue May 13 21:59:54 1997
@@ -0,0 +1,157 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *   
+ * linux/fs/autofs/autofs_i.h
+ *
+ *   Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Internal header file for autofs */
+
+#include <linux/auto_fs.h>
+
+/* This is the range of ioctl() numbers we claim as ours */
+#define AUTOFS_IOC_FIRST     AUTOFS_IOC_READY
+#define AUTOFS_IOC_COUNT     32
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+
+#if LINUX_VERSION_CODE < 0x20100
+
+/* Segmentation stuff for pre-2.1 kernels */
+#include <asm/segment.h>
+#define copy_to_user	memcpy_tofs
+#define copy_from_user	memcpy_fromfs
+
+#else
+
+/* Segmentation stuff for post-2.1 kernels */
+#include <asm/uaccess.h>
+#define register_symtab(x)	((void)0)
+
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(D) printk D;
+#else
+#define DPRINTK(D)
+#endif
+
+#define AUTOFS_SUPER_MAGIC 0x0187
+
+/* Structures associated with the root directory hash */
+
+#define AUTOFS_HASH_SIZE 67
+
+typedef u32 autofs_hash_t;	/* Type returned by autofs_hash() */
+
+struct autofs_dir_ent {
+	autofs_hash_t hash;
+	struct autofs_dir_ent *next;
+	struct autofs_dir_ent **back;
+	char *name;
+	int len;
+	ino_t ino;
+	/* The following entries are for the expiry system */
+	unsigned long last_usage;
+	struct autofs_dir_ent *exp_next;
+	struct autofs_dir_ent *exp_prev;
+};
+
+struct autofs_dirhash {
+	struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
+	struct autofs_dir_ent expiry_head;
+};
+
+struct autofs_wait_queue {
+	unsigned long wait_queue_token;
+	struct wait_queue *queue;
+	struct autofs_wait_queue *next;
+	/* We use the following to see what we are waiting for */
+	autofs_hash_t hash;
+	int len;
+	char *name;
+	/* This is for status reporting upon return */
+	int status;
+	int wait_ctr;
+};
+
+struct autofs_symlink {
+	int len;
+	char *data;
+	time_t mtime;
+};
+
+#define AUTOFS_MAX_SYMLINKS 256
+
+#define AUTOFS_ROOT_INO      1
+#define AUTOFS_FIRST_SYMLINK 2
+#define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS)
+
+#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)
+
+#ifndef END_OF_TIME
+#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
+#endif
+
+struct autofs_sb_info {
+	struct file *pipe;
+	pid_t oz_pgrp;
+	int catatonic;
+	unsigned long exp_timeout;
+	ino_t next_dir_ino;
+	struct autofs_wait_queue *queues; /* Wait queue pointer */
+	struct autofs_dirhash dirhash; /* Root directory hash */
+	struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS];
+	u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
+};
+
+/* autofs_oz_mode(): do we see the man behind the curtain? */
+static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
+	return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
+}
+
+/* Hash operations */
+
+autofs_hash_t autofs_hash(const char *,int);
+void autofs_initialize_hash(struct autofs_dirhash *);
+struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
+void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
+void autofs_hash_delete(struct autofs_dir_ent *);
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
+void autofs_hash_nuke(struct autofs_dirhash *);
+
+/* Expiration-handling functions */
+
+void autofs_update_usage(struct autofs_dirhash *,struct autofs_dir_ent *);
+struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *,unsigned long);
+
+/* Operations structures */
+
+extern struct inode_operations autofs_root_inode_operations;
+extern struct inode_operations autofs_symlink_inode_operations;
+extern struct inode_operations autofs_dir_inode_operations;
+
+/* Initializing function */
+
+struct super_block *autofs_read_super(struct super_block *, void *,int);
+
+/* Queue management functions */
+
+int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
+int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
+void autofs_catatonic_mode(struct autofs_sb_info *);
+
+#ifdef DEBUG
+void autofs_say(const char *name, int len);
+#else
+#define autofs_say(n,l)
+#endif
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.1.36/linux/fs/autofs/dir.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/dir.c	Mon May 12 10:35:42 1997
@@ -10,7 +10,7 @@
  *
  * ------------------------------------------------------------------------- */
 
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
 
 static int autofs_dir_readdir(struct inode *inode, struct file *filp,
 			       void *dirent, filldir_t filldir)
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c
--- v2.1.36/linux/fs/autofs/dirhash.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/dirhash.c	Mon May 12 10:35:42 1997
@@ -10,9 +10,43 @@
  *
  * ------------------------------------------------------------------------- */
 
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
+
+/* Functions for maintenance of expiry queue */
+
+static void autofs_init_usage(struct autofs_dirhash *dh,
+			      struct autofs_dir_ent *ent)
+{
+	ent->exp_next = &dh->expiry_head;
+	ent->exp_prev = dh->expiry_head.exp_prev;
+	dh->expiry_head.exp_prev->exp_next = ent;
+	dh->expiry_head.exp_prev = ent;
+	ent->last_usage = jiffies;
+}
+
+static void autofs_delete_usage(struct autofs_dir_ent *ent)
+{
+	ent->exp_prev->exp_next = ent->exp_next;
+	ent->exp_next->exp_prev = ent->exp_prev;
+}
+
+void autofs_update_usage(struct autofs_dirhash *dh,
+			 struct autofs_dir_ent *ent)
+{
+	autofs_delete_usage(ent);   /* Unlink from current position */
+	autofs_init_usage(dh,ent);  /* Relink at queue tail */
+}
+
+struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *dh,
+				     unsigned long timeout)
+{
+	struct autofs_dir_ent *ent;
+
+	ent = dh->expiry_head.exp_next;
+
+	if ( ent == &(dh->expiry_head) ) return NULL;
+	return (jiffies - ent->last_usage >= timeout) ? ent : NULL;
+}
 
 /* Adapted from the Dragon Book, page 436 */
 /* This particular hashing algorithm requires autofs_hash_t == u32 */
@@ -28,6 +62,8 @@
 
 void autofs_initialize_hash(struct autofs_dirhash *dh) {
 	memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
+	dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
+		&dh->expiry_head;
 }
 
 struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, autofs_hash_t hash, const char *name, int len)
@@ -54,6 +90,8 @@
 	DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash));
 	autofs_say(ent->name,ent->len);
 
+	autofs_init_usage(dh,ent);
+
 	dhnp = &dh->h[ent->hash % AUTOFS_HASH_SIZE];
 	ent->next = *dhnp;
 	ent->back = dhnp;
@@ -63,6 +101,9 @@
 void autofs_hash_delete(struct autofs_dir_ent *ent)
 {
 	*(ent->back) = ent->next;
+
+	autofs_delete_usage(ent);
+
 	kfree(ent->name);
 	kfree(ent);
 }
@@ -114,6 +155,8 @@
 	return ent;
 }
 
+/* Delete everything.  This is used on filesystem destruction, so we
+   make no attempt to keep the pointers valid */
 void autofs_hash_nuke(struct autofs_dirhash *dh)
 {
 	int i;
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/init.c linux/fs/autofs/init.c
--- v2.1.36/linux/fs/autofs/init.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/autofs/init.c	Mon May 12 10:35:42 1997
@@ -10,24 +10,20 @@
  *
  * ------------------------------------------------------------------------- */
 
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
 
-struct file_system_type autofs_fs_type = {
+static struct file_system_type autofs_fs_type = {
 	autofs_read_super, "autofs", 0, NULL
 };
 
-int init_autofs_fs(void)
-{
-	return register_filesystem(&autofs_fs_type);
-}
-
 #ifdef MODULE
 int init_module(void)
 {
 	int status;
 	
-	if ((status = init_autofs_fs()) == 0)
+	if ((status = register_filesystem(&autofs_fs_type)) == 0)
 		register_symtab(0);
 	return status;
 }
@@ -36,7 +32,15 @@
 {
 	unregister_filesystem(&autofs_fs_type);
 }
-#endif
+
+#else /* MODULE */
+
+__initfunc(int init_autofs_fs(void))
+{
+	return register_filesystem(&autofs_fs_type);
+}
+
+#endif /* !MODULE */
 
 #ifdef DEBUG
 void autofs_say(const char *name, int len)
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.1.36/linux/fs/autofs/inode.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/inode.c	Mon May 12 10:35:42 1997
@@ -15,7 +15,7 @@
 #include <linux/file.h>
 #include <linux/locks.h>
 #include <asm/bitops.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -28,17 +28,19 @@
 
 static void autofs_put_super(struct super_block *sb)
 {
-	struct autofs_sb_info *sbi;
+	struct autofs_sb_info *sbi =
+		(struct autofs_sb_info *) sb->u.generic_sbp;
 	unsigned int n;
 
+	if ( !sbi->catatonic )
+		autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
+
         lock_super(sb);
-	sbi = (struct autofs_sb_info *) sb->u.generic_sbp;
 	autofs_hash_nuke(&sbi->dirhash);
 	for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
 		if ( test_bit(n, sbi->symlink_bitmap) )
 			kfree(sbi->symlink[n].data);
 	}
-	fput(sbi->pipe, sbi->pipe->f_inode);
 
         sb->s_dev = 0;
 	kfree(sb->u.generic_sbp);
@@ -149,6 +151,7 @@
 
 	s->u.generic_sbp = sbi;
 	sbi->catatonic = 0;
+	sbi->exp_timeout = 0;
 	sbi->oz_pgrp = current->pgrp;
 	autofs_initialize_hash(&sbi->dirhash);
 	sbi->queues = NULL;
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.36/linux/fs/autofs/root.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/root.c	Mon May 12 10:35:42 1997
@@ -12,9 +12,8 @@
 
 #include <linux/errno.h>
 #include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/ioctl.h>
-#include <linux/auto_fs.h>
+#include <linux/param.h>
+#include "autofs_i.h"
 
 static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
 static int autofs_root_lookup(struct inode *,const char *,int,struct inode **);
@@ -171,7 +170,8 @@
 			}
 		}
 	} while(!res);
-		
+	autofs_update_usage(&sbi->dirhash,ent);
+	
 	*result = res;
 	iput(dir);
 	return 0;
@@ -229,7 +229,6 @@
 	ent->ino = AUTOFS_FIRST_SYMLINK + n;
 	ent->hash = hash;
 	memcpy(ent->name,name,ent->len = len);
-	ent->expiry = END_OF_TIME;
 
 	autofs_hash_insert(dh,ent);
 
@@ -322,7 +321,6 @@
 	ent->hash = hash;
 	memcpy(ent->name, name, ent->len = len);
 	ent->ino = sbi->next_dir_ino++;
-	ent->expiry = END_OF_TIME;
 	autofs_hash_insert(dh,ent);
 	dir->i_nlink++;
 	iput(dir);
@@ -330,6 +328,52 @@
 	return 0;
 }
 
+/* Get/set timeout ioctl() operation */
+static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
+					 unsigned long *p)
+{
+	int rv;
+	unsigned long ntimeout;
+
+	if ( (rv = get_user(ntimeout, p)) ||
+	     (rv = put_user(sbi->exp_timeout/HZ, p)) )
+		return rv;
+
+	if ( ntimeout > ULONG_MAX/HZ )
+		sbi->exp_timeout = 0;
+	else
+		sbi->exp_timeout = ntimeout * HZ;
+
+	return 0;
+}
+
+/* Perform an expiry operation */
+static inline int autofs_expire_run(struct autofs_sb_info *sbi,
+				    struct autofs_packet_expire *pkt_p)
+{
+	struct autofs_dir_ent *ent;
+	struct autofs_packet_expire pkt;
+	struct autofs_dirhash *dh = &(sbi->dirhash);
+	
+	pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
+	pkt.hdr.type = autofs_ptype_expire;
+
+	if ( !sbi->exp_timeout ||
+	     !(ent = autofs_expire(dh,sbi->exp_timeout)) )
+		return -EAGAIN;
+
+	pkt.len = ent->len;
+	memcpy(pkt.name, ent->name, pkt.len);
+	pkt.name[pkt.len] = '\0';
+
+	if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+		return -EFAULT;
+	
+	autofs_update_usage(dh,ent);
+
+	return 0;
+}
+
 /*
  * ioctl()'s on the root directory is the chief method for the daemon to
  * generate kernel reactions
@@ -337,26 +381,33 @@
 static int autofs_root_ioctl(struct inode *inode, struct file *filp,
 			     unsigned int cmd, unsigned long arg)
 {
-	struct autofs_sb_info *sbi = (struct autofs_sb_info *)inode->i_sb->u.generic_sbp;
+	struct autofs_sb_info *sbi =
+		(struct autofs_sb_info *)inode->i_sb->u.generic_sbp;
 
-	DPRINTK(("autofs_ioctl: cmd = %04x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));
+	DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));
 
+	if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+		return -ENOTTY;
+	
+	if ( !autofs_oz_mode(sbi) && !fsuser() )
+		return -EPERM;
+	
 	switch(cmd) {
 	case AUTOFS_IOC_READY:	/* Wait queue: go ahead and retry */
-		if ( !autofs_oz_mode(sbi) && !fsuser() )
-			return -EPERM;
 		return autofs_wait_release(sbi,arg,0);
 	case AUTOFS_IOC_FAIL:	/* Wait queue: fail with ENOENT */
-		/* Optional: add to failure cache */
-		if ( !autofs_oz_mode(sbi) && !fsuser() )
-			return -EPERM;
 		return autofs_wait_release(sbi,arg,-ENOENT);
 	case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
-		if ( !autofs_oz_mode(sbi) && !fsuser() )
-			return -EPERM;
 		autofs_catatonic_mode(sbi);
 		return 0;
+	case AUTOFS_IOC_PROTOVER: /* Get protocol version */
+		return put_user(AUTOFS_PROTO_VERSION, (int *)arg);
+	case AUTOFS_IOC_SETTIMEOUT:
+		return autofs_get_set_timeout(sbi,(unsigned long *)arg);
+	case AUTOFS_IOC_EXPIRE:
+		return autofs_expire_run(sbi,(struct autofs_packet_expire *)arg);
 	default:
-		return -ENOTTY;	/* Should this be ENOSYS? */
+		return -ENOSYS;
 	}
 }
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.1.36/linux/fs/autofs/symlink.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/symlink.c	Mon May 12 10:35:42 1997
@@ -12,7 +12,7 @@
 
 #include <linux/string.h>
 #include <linux/sched.h>
-#include <linux/auto_fs.h>
+#include "autofs_i.h"
 
 static int autofs_follow_link(struct inode *dir, struct inode *inode,
 			      int flag, int mode, struct inode **res_inode)
diff -u --recursive --new-file v2.1.36/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.36/linux/fs/autofs/waitq.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/autofs/waitq.c	Mon May 12 10:35:42 1997
@@ -11,9 +11,10 @@
  * ------------------------------------------------------------------------- */
 
 #include <linux/malloc.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/auto_fs.h>
+#include <linux/signal.h>
+#include <linux/file.h>
+#include "autofs_i.h"
 
 /* We make this a static variable rather than a part of the superblock; it
    is better if we don't reassign numbers easily even across filesystems */
@@ -36,6 +37,7 @@
 		wake_up(&wq->queue);
 		wq = nwq;
 	}
+	fput(sbi->pipe, sbi->pipe->f_inode);	/* Close the pipe */
 }
 
 static int autofs_write(struct file *file, const void *addr, int bytes)
diff -u --recursive --new-file v2.1.36/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.36/linux/fs/binfmt_elf.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/binfmt_elf.c	Mon May 12 17:39:50 1997
@@ -210,14 +210,16 @@
 
 	/* Now read in all of the header information */
 
-	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
 	    return ~0UL;
+	}
 
 	elf_phdata =  (struct elf_phdr *)
 		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
 			GFP_KERNEL);
-	if (!elf_phdata)
+	if (!elf_phdata) {
 	  return ~0UL;
+	}
 
 	/*
 	 * If the size of this structure has changed, then punt, since
@@ -278,6 +280,7 @@
 	      /* Real error */
 	      sys_close(elf_exec_fileno);
 	      kfree(elf_phdata);
+printk("%d", error);
 	      return ~0UL;
 	    }
 
@@ -359,7 +362,9 @@
 	    interp_ex->a_bss,
 	    PROT_READ|PROT_WRITE|PROT_EXEC,
 	    MAP_FIXED|MAP_PRIVATE, 0);
-  if (retval < 0) return ~0UL;
+  if (retval < 0) {
+  	return ~0UL;
+  }
   return elf_entry;
 }
 
@@ -1154,7 +1159,8 @@
 		set_fs(fs);
 
 		len = current->mm->arg_end - current->mm->arg_start;
-		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+		if (len >= ELF_PRARGSZ)
+			len = ELF_PRARGSZ-1;
 		copy_from_user(&psinfo.pr_psargs,
 			      (const char *)current->mm->arg_start, len);
 		for(i = 0; i < len; i++)
diff -u --recursive --new-file v2.1.36/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.36/linux/fs/buffer.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/buffer.c	Mon May 12 10:35:42 1997
@@ -1120,11 +1120,11 @@
 /* Run the hooks that have to be done when a page I/O has completed. */
 static inline void after_unlock_page (struct page * page)
 {
-	if (clear_bit(PG_decr_after, &page->flags))
+	if (test_and_clear_bit(PG_decr_after, &page->flags))
 		atomic_dec(&nr_async_pages);
-	if (clear_bit(PG_free_after, &page->flags))
+	if (test_and_clear_bit(PG_free_after, &page->flags))
 		__free_page(page);
-	if (clear_bit(PG_swap_unlock_after, &page->flags))
+	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
 		swap_after_unlock_page(page->swap_unlock_entry);
 }
 
diff -u --recursive --new-file v2.1.36/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.36/linux/fs/dcache.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/dcache.c	Mon May 12 10:35:42 1997
@@ -153,17 +153,24 @@
 /*
  * Find a directory cache entry given all the necessary info.
  */
-static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, int len, struct dir_cache_entry ** hash)
+static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, unsigned char len, struct dir_cache_entry ** hash)
 {
 	struct dir_cache_entry *de;
 
-	for(de = *hash; de; de = de->next)
+	de = *hash;
+	goto inside;
+	for (;;) {
+		de = de->next;
+inside:
+		if (!de)
+			break;
 		if((de->name_len == (unsigned char) len)	&&
 		   (de->dc_dev == dir->i_dev)			&&
 		   (de->dir == dir->i_ino)			&&
 		   (de->version == dir->i_version)		&&
 		   (!memcmp(de->name, name, len)))
 			break;
+	}
 	return de;
 }
 
@@ -195,7 +202,7 @@
 		struct dir_cache_entry *de;
 
 		spin_lock(&dcache_lock);
-		de = find_entry(dir, name, len, hash);
+		de = find_entry(dir, name, (unsigned char) len, hash);
 		if(de) {
 			*ino = de->ino;
 			move_to_level2(de, hash);
@@ -213,7 +220,7 @@
 		struct dir_cache_entry *de;
 
 		spin_lock(&dcache_lock);
-		de = find_entry(dir, name, len, hash);
+		de = find_entry(dir, name, (unsigned char) len, hash);
 		if (de) {
 			de->ino = ino;
 			update_lru(de);
diff -u --recursive --new-file v2.1.36/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.36/linux/fs/dquot.c	Sun Jan 26 02:07:30 1997
+++ linux/fs/dquot.c	Mon May 12 10:35:42 1997
@@ -33,6 +33,7 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/tty.h>
+#include <linux/file.h>
 #include <linux/malloc.h>
 #include <linux/mount.h>
 #include <linux/smp.h>
@@ -989,7 +990,7 @@
 			}
 		} else
 			error = -EIO;
-	  filp->f_count--;
+		put_filp(filp);
 	} else
 		error = -EMFILE;
 	iput(inode);
diff -u --recursive --new-file v2.1.36/linux/fs/exec.c linux/fs/exec.c
--- v2.1.36/linux/fs/exec.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/exec.c	Mon May 12 10:35:42 1997
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <linux/mman.h>
 #include <linux/a.out.h>
 #include <linux/errno.h>
@@ -36,7 +37,6 @@
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/malloc.h>
 #include <linux/binfmts.h>
 #include <linux/personality.h>
 #include <linux/smp.h>
@@ -148,7 +148,7 @@
 		if (f->f_op->open) {
 			int error = f->f_op->open(inode,f);
 			if (error) {
-				f->f_count--;
+				put_filp(f);
 				put_unused_fd(fd);
 				return error;
 			}
@@ -384,7 +384,7 @@
 	 * (the oom is wrong there, too, IMHO)
 	 */
 	if (current->mm->count > 1) {
-		struct mm_struct *mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+		struct mm_struct *mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
 		if (!mm) {
 			/* this is wrong, I think. */
 			oom(current);
@@ -394,8 +394,7 @@
 		init_new_context(mm);
 		mm->def_flags = 0;	/* should future lockings be kept? */
 		mm->count = 1;
-		mm->mmap = NULL;
-		mm->mmap_avl = NULL;
+		mm->mmap = mm->mmap_cache = NULL;
 		mm->total_vm = 0;
 		mm->rss = 0;
 		current->mm->count--;
diff -u --recursive --new-file v2.1.36/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.1.36/linux/fs/ext2/balloc.c	Thu Nov 14 00:27:37 1996
+++ linux/fs/ext2/balloc.c	Mon May 12 10:35:42 1997
@@ -177,6 +177,7 @@
 	unsigned long bit;
 	unsigned long i;
 	int bitmap_nr;
+	unsigned long overflow;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
 	struct ext2_super_block * es;
@@ -199,14 +200,20 @@
 
 	ext2_debug ("freeing block %lu\n", block);
 
+do_more:
+	overflow = 0;
 	block_group = (block - le32_to_cpu(es->s_first_data_block)) /
 		      EXT2_BLOCKS_PER_GROUP(sb);
-	bit = (block - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb);
-	if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
-		ext2_panic (sb, "ext2_free_blocks",
-			    "Freeing blocks across group boundary - "
-			    "Block = %lu, count = %lu",
-			    block, count);
+	bit = (block - le32_to_cpu(es->s_first_data_block)) %
+		      EXT2_BLOCKS_PER_GROUP(sb);
+	/*
+	 * Check to see if we are freeing blocks across a group
+	 * boundary.
+	 */
+	if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) {
+		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
+		count -= overflow;
+	}
 	bitmap_nr = load_block_bitmap (sb, block_group);
 	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	gdp = get_group_desc (sb, block_group, &bh2);
@@ -246,6 +253,11 @@
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
 	}
+	if (overflow) {
+		block += count;
+		count = overflow;
+		goto do_more;
+	}
 	sb->s_dirt = 1;
 	unlock_super (sb);
 	return;
@@ -546,6 +558,19 @@
 			 EXT2_BLOCKS_PER_GROUP(sb), map);
 }
 
+static int test_root(int a, int b)
+{
+	if (a == 0)
+		return 1;
+	while (1) {
+		if (a == 1)
+			return 1;
+		if (a % b)
+			return 0;
+		a = a / b;
+	}
+}
+
 void ext2_check_blocks_bitmap (struct super_block * sb)
 {
 	struct buffer_head * bh;
@@ -569,15 +594,21 @@
 		bitmap_nr = load_block_bitmap (sb, i);
 		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
-		if (!ext2_test_bit (0, bh->b_data))
-			ext2_error (sb, "ext2_check_blocks_bitmap",
-				    "Superblock in group %d is marked free", i);
-
-		for (j = 0; j < desc_blocks; j++)
-			if (!ext2_test_bit (j + 1, bh->b_data))
+		if (!(sb->u.ext2_sb.s_feature_ro_compat &
+		     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+		    (test_root(i, 3) || test_root(i, 5) || test_root(i, 7))) {
+			if (!ext2_test_bit (0, bh->b_data))
 				ext2_error (sb, "ext2_check_blocks_bitmap",
+					    "Superblock in group %d "
+					    "is marked free", i);
+
+			for (j = 0; j < desc_blocks; j++)
+				if (!ext2_test_bit (j + 1, bh->b_data))
+					ext2_error (sb,
+					    "ext2_check_blocks_bitmap",
 					    "Descriptor block #%d in group "
 					    "%d is marked free", j, i);
+		}
 
 		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
diff -u --recursive --new-file v2.1.36/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.1.36/linux/fs/ext2/inode.c	Sun Dec 22 06:16:53 1996
+++ linux/fs/ext2/inode.c	Mon May 12 10:35:42 1997
@@ -503,12 +503,23 @@
 		inode->i_op = &blkdev_inode_operations;
 	else if (S_ISFIFO(inode->i_mode))
 		init_fifo(inode);
-	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
+	inode->i_attr_flags = 0;
+	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
 		inode->i_flags |= MS_SYNCHRONOUS;
-	if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL)
+	}
+	if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_APPEND;
 		inode->i_flags |= S_APPEND;
-	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)
+	}
+	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
 		inode->i_flags |= S_IMMUTABLE;
+	}
+	if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
+		inode->i_flags |= MS_NOATIME;
+	}
 }
 
 static int ext2_update_inode(struct inode * inode, int do_sync)
@@ -597,11 +608,71 @@
 
 void ext2_write_inode (struct inode * inode)
 {
+#if 0
+	printk("ext2_write(%04x:%06d)...", inode->i_dev, inode->i_ino);
+#endif
 	ext2_update_inode (inode, 0);
 }
 
 int ext2_sync_inode (struct inode *inode)
 {
+#if 0
+	printk("ext2_sync(%04x:%06d)...", inode->i_dev, inode->i_ino);
+#endif
 	return ext2_update_inode (inode, 1);
+}
+
+int ext2_notify_change(struct inode *inode, struct iattr *iattr)
+{
+	int		retval;
+	unsigned int	flags;
+	
+	if ((iattr->ia_attr_flags &
+	     (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
+	    (inode->u.ext2_i.i_flags &
+	     (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+		if (!fsuser() || securelevel > 0)
+			return -EPERM;
+	} else
+		if ((current->fsuid != inode->i_uid) && !fsuser())
+			return -EPERM;
+
+	if ((retval = inode_change_ok(inode, iattr)) != 0)
+		return retval;
+
+	inode_setattr(inode, iattr);
+	
+	flags = iattr->ia_attr_flags;
+	if (flags & ATTR_FLAG_SYNCRONOUS) {
+		inode->i_flags |= MS_SYNCHRONOUS;
+		inode->u.ext2_i.i_flags = EXT2_SYNC_FL;
+	} else {
+		inode->i_flags &= ~MS_SYNCHRONOUS;
+		inode->u.ext2_i.i_flags &= ~EXT2_SYNC_FL;
+	}
+	if (flags & ATTR_FLAG_NOATIME) {
+		inode->i_flags |= MS_NOATIME;
+		inode->u.ext2_i.i_flags = EXT2_NOATIME_FL;
+	} else {
+		inode->i_flags &= ~MS_NOATIME;
+		inode->u.ext2_i.i_flags &= ~EXT2_NOATIME_FL;
+	}
+	if (flags & ATTR_FLAG_APPEND) {
+		inode->i_flags |= S_APPEND;
+		inode->u.ext2_i.i_flags = EXT2_APPEND_FL;
+	} else {
+		inode->i_flags &= ~S_APPEND;
+		inode->u.ext2_i.i_flags &= ~EXT2_APPEND_FL;
+	}
+	if (flags & ATTR_FLAG_IMMUTABLE) {
+		inode->i_flags |= S_IMMUTABLE;
+		inode->u.ext2_i.i_flags = EXT2_IMMUTABLE_FL;
+	} else {
+		inode->i_flags &= ~S_IMMUTABLE;
+		inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
+	}
+	inode->i_dirt = 1;
+
+	return 0;
 }
 
diff -u --recursive --new-file v2.1.36/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v2.1.36/linux/fs/ext2/ioctl.c	Tue Dec 31 11:19:32 1996
+++ linux/fs/ext2/ioctl.c	Mon May 12 10:35:42 1997
@@ -45,6 +45,10 @@
 		if (IS_RDONLY(inode))
 			return -EROFS;
 		inode->u.ext2_i.i_flags = flags;
+		if (flags & EXT2_SYNC_FL)
+			inode->i_flags |= MS_SYNCHRONOUS;
+		else
+			inode->i_flags &= ~MS_SYNCHRONOUS;
 		if (flags & EXT2_APPEND_FL)
 			inode->i_flags |= S_APPEND;
 		else
@@ -53,6 +57,10 @@
 			inode->i_flags |= S_IMMUTABLE;
 		else
 			inode->i_flags &= ~S_IMMUTABLE;
+		if (flags & EXT2_NOATIME_FL)
+			inode->i_flags |= MS_NOATIME;
+		else
+			inode->i_flags &= ~MS_NOATIME;
 		inode->i_ctime = CURRENT_TIME;
 		inode->i_dirt = 1;
 		return 0;
diff -u --recursive --new-file v2.1.36/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.36/linux/fs/ext2/namei.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/ext2/namei.c	Mon May 12 10:35:42 1997
@@ -583,7 +583,7 @@
 	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
 	de = (struct ext2_dir_entry *) ((char *) de1 + le16_to_cpu(de1->rec_len));
 	while (offset < inode->i_size ) {
-		if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 			brelse (bh);
 			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
 			if (!bh) {
diff -u --recursive --new-file v2.1.36/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.1.36/linux/fs/ext2/super.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/ext2/super.c	Mon May 12 10:35:42 1997
@@ -508,6 +508,9 @@
 			goto failed_mount;
 		}
 	}
+	sb->u.ext2_sb.s_feature_compat = es->s_feature_compat;
+	sb->u.ext2_sb.s_feature_incompat = es->s_feature_incompat;
+	sb->u.ext2_sb.s_feature_ro_compat = es->s_feature_ro_compat;
 	sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
 				   (__s32) le32_to_cpu(es->s_log_frag_size);
 	if (sb->u.ext2_sb.s_frag_size)
diff -u --recursive --new-file v2.1.36/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.1.36/linux/fs/fcntl.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/fcntl.c	Mon May 12 10:35:42 1997
@@ -163,6 +163,7 @@
 			if (current->pgrp == -arg || current->pid == arg)
 				goto fasync_ok;
 			
+			read_lock(&tasklist_lock);
 			for_each_task(p) {
 				if ((p->pid == arg) || (p->pid == -arg) || 
 				    (p->pgrp == -arg)) {
@@ -171,11 +172,14 @@
 					if ((p->session != current->session) &&
 					    (p->uid != current->uid) &&
 					    (p->euid != current->euid) &&
-					    !suser())
+					    !suser()) {
+						read_unlock(&tasklist_lock);
 						goto out;
+					}
 					break;
 				}
 			}
+			read_unlock(&tasklist_lock);
 			err = -EINVAL;
 			if ((task_found == 0) && !suser())
 				break;
diff -u --recursive --new-file v2.1.36/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.36/linux/fs/file_table.c	Sat Aug  3 00:43:18 1996
+++ linux/fs/file_table.c	Mon May 12 10:35:42 1997
@@ -2,143 +2,104 @@
  *  linux/fs/file_table.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 
-/*
- * first_file points to a doubly linked list of all file structures in
- *            the system.
- * nr_files   holds the length of this list.
- */
-struct file * first_file = NULL;
+/* SLAB cache for filp's. */
+static kmem_cache_t *filp_cache;
+
+/* sysctl tunables... */
 int nr_files = 0;
 int max_files = NR_FILE;
 
-/*
- * Insert a new file structure at the head of the list of available ones.
- */
-static inline void insert_file_free(struct file *file)
-{
-	struct file *next, *prev;
+/* Free list management, if you are here you must have f_count == 0 */
+static struct file * free_filps = NULL;
 
-	next = first_file;
-	first_file = file;
-	file->f_count = 0;
-	prev = next->f_prev;
-	file->f_next = next;
-	next->f_prev = file;
-	file->f_prev = prev;
-	prev->f_next = file;
-}
-
-/*
- * Remove a file structure from the list of available ones.
- */
-static inline void remove_file_free(struct file *file)
+void insert_file_free(struct file *file)
 {
-	struct file *next, *prev;
-
-	next = file->f_next;
-	prev = file->f_prev;
-	file->f_next = file->f_prev = NULL;
-	if (first_file == file)
-		first_file = next;
-	next->f_prev = prev;
-	prev->f_next = next;
+	if((file->f_next = free_filps) != NULL)
+		free_filps->f_pprev = &file->f_next;
+	free_filps = file;
+	file->f_pprev = &free_filps;
 }
 
-/*
- * Insert a file structure at the end of the list of available ones.
- */
-static inline void put_last_free(struct file *file)
+/* The list of in-use filp's must be exported (ugh...) */
+struct file *inuse_filps = NULL;
+
+static inline void put_inuse(struct file *file)
 {
-	struct file *next, *prev;
+	if((file->f_next = inuse_filps) != NULL)
+		inuse_filps->f_pprev = &file->f_next;
+	inuse_filps = file;
+	file->f_pprev = &inuse_filps;
+}
 
-	next = first_file;
-	file->f_next = next;
-	prev = next->f_prev;
-	next->f_prev = file;
-	file->f_prev = prev;
-	prev->f_next = file;
-}
-
-/*
- * Allocate a new memory page for file structures and
- * insert the new structures into the global list.
- * Returns 0, if there is no more memory, 1 otherwise.
- */
+/* Get more free filp's. */
 static int grow_files(void)
 {
-	struct file * file;
-	int i;
-
-	/*
-	 * We don't have to clear the page because we only look into
-	 * f_count, f_prev and f_next and they get initialized in
-	 * insert_file_free.  The rest of the file structure is cleared
-	 * by get_empty_filp before it is returned.
-	 */
-	file = (struct file *) __get_free_page(GFP_KERNEL);
-
-	if (!file)
-		return 0;
-
-	nr_files += i = PAGE_SIZE/sizeof(struct file);
-
-	if (!first_file)
-		file->f_count = 0,
-		file->f_next = file->f_prev = first_file = file++,
-		i--;
+	int i = 16;
 
-	for (; i ; i--)
-		insert_file_free(file++);
+	while(i--) {
+		struct file * file = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
+		if(!file) {
+			if(i == 15)
+				return 0;
+			goto got_some;
+		}
 
+		insert_file_free(file);
+		nr_files++;
+	}
+got_some:
 	return 1;
 }
 
-unsigned long file_table_init(unsigned long start, unsigned long end)
+void file_table_init(void)
 {
-	return start;
+	filp_cache = kmem_cache_create("filp", sizeof(struct file),
+				       sizeof(unsigned long) * 8,
+				       SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if(!filp_cache)
+		panic("VFS: Cannot alloc filp SLAB cache.");
 }
 
-/*
- * Find an unused file structure and return a pointer to it.
+/* Find an unused file structure and return a pointer to it.
  * Returns NULL, if there are no more free file structures or
  * we run out of memory.
  */
 struct file * get_empty_filp(void)
 {
-	int i;
-	int max = max_files;
 	struct file * f;
 
-	/*
-	 * Reserve a few files for the super-user..
-	 */
-	if (current->euid)
-		max -= 10;
-
-	/* if the return is taken, we are in deep trouble */
-	if (!first_file && !grow_files())
-		return NULL;
-
-	do {
-		for (f = first_file, i=0; i < nr_files; i++, f = f->f_next)
-			if (!f->f_count) {
-				remove_file_free(f);
-				memset(f,0,sizeof(*f));
-				put_last_free(f);
-				f->f_count = 1;
-				f->f_version = ++event;
-				return f;
-			}
-	} while (nr_files < max && grow_files());
+again:
+	if((f = free_filps) != NULL) {
+		remove_filp(f);
+		memset(f, 0, sizeof(*f));
+		f->f_count = 1;
+		f->f_version = ++event;
+		put_inuse(f);
+	} else {
+		int max = max_files;
+
+		/* Reserve a few files for the super-user.. */
+		if (current->euid)
+			max -= 10;
 
-	return NULL;
+		if (nr_files < max && grow_files())
+			goto again;
+
+		/* Big problems... */
+	}
+	return f;
 }
 
 #ifdef CONFIG_QUOTA
@@ -146,10 +107,9 @@
 void add_dquot_ref(kdev_t dev, short type)
 {
 	struct file *filp;
-	int cnt;
 
-	for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
-		if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+	for (filp = inuse_filps; filp; filp = filp->f_next) {
+		if (!filp->f_inode || filp->f_inode->i_dev != dev)
 			continue;
 		if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) {
 			filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type);
@@ -161,10 +121,9 @@
 void reset_dquot_ptrs(kdev_t dev, short type)
 {
 	struct file *filp;
-	int cnt;
 
-	for (filp = first_file, cnt = 0; cnt < nr_files; cnt++, filp = filp->f_next) {
-		if (!filp->f_count || !filp->f_inode || filp->f_inode->i_dev != dev)
+	for (filp = inuse_filps; filp; filp = filp->f_next) {
+		if (!filp->f_inode || filp->f_inode->i_dev != dev)
 			continue;
 		if (IS_WRITABLE(filp->f_inode)) {
 			filp->f_inode->i_dquot[type] = NODQUOT;
diff -u --recursive --new-file v2.1.36/linux/fs/inode.c linux/fs/inode.c
--- v2.1.36/linux/fs/inode.c	Wed Apr 23 19:01:24 1997
+++ linux/fs/inode.c	Mon May 12 10:35:42 1997
@@ -232,12 +232,10 @@
 int fs_may_remount_ro(kdev_t dev)
 {
 	struct file * file;
-	int i;
 
 	/* Check that no files are currently opened for writing. */
-	for (file = first_file, i=0; i<nr_files; i++, file=file->f_next) {
-		if (!file->f_count || !file->f_inode ||
-		    file->f_inode->i_dev != dev)
+	for (file = inuse_filps; file; file = file->f_next) {
+		if (!file->f_inode || file->f_inode->i_dev != dev)
 			continue;
 		if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2))
 			return 0;
@@ -288,7 +286,7 @@
 
 		   ((attr->ia_valid & ATTR_GID) &&
 		    (!in_group_p(attr->ia_gid) &&
-		     (attr->ia_gid != inode->i_gid)))		||
+		     (attr->ia_gid != inode->i_gid)) && not_fsuser)	||
 
 		   ((attr->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)) &&
 		    (fsuid != iuid) && not_fsuser))
@@ -325,6 +323,8 @@
 		if (!fsuser() && !in_group_p(inode->i_gid))
 			inode->i_mode &= ~S_ISGID;
 	}
+	if (attr->ia_valid & ATTR_ATTR_FLAG)
+		inode->i_attr_flags = attr->ia_attr_flags;
 	inode->i_dirt = 1;
 }
 
diff -u --recursive --new-file v2.1.36/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.36/linux/fs/isofs/inode.c	Wed Apr 23 19:01:25 1997
+++ linux/fs/isofs/inode.c	Tue May 13 11:41:47 1997
@@ -138,13 +138,7 @@
 			  !strcmp(this_char,"uid") ||
 			  !strcmp(this_char,"gid"))) {
 		  char * vpnt = value;
-		  unsigned int ivalue;
-		  ivalue = 0;
-		  while(*vpnt){
-		    if(*vpnt <  '0' || *vpnt > '9') break;
-		    ivalue = ivalue * 10 + (*vpnt - '0');
-		    vpnt++;
-		  }
+		  unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
 		  if (*vpnt) return 0;
 		  switch(*this_char) {
 		  case 'b':
diff -u --recursive --new-file v2.1.36/linux/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c
--- v2.1.36/linux/fs/lockd/svcsubs.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/lockd/svcsubs.c	Mon May 12 10:35:42 1997
@@ -228,12 +228,12 @@
 	down(&nlm_file_sema);
 
 	/* If there are no more locks etc, delete the file */
-	if (--(file->f_count) == 0
-	 && !nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
-		nlm_delete_file(file);
+	if(--file->f_count == 0) {
+		if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
+			nlm_delete_file(file);
+	}
 
 	up(&nlm_file_sema);
-	return;
 }
 
 /*
diff -u --recursive --new-file v2.1.36/linux/fs/locks.c linux/fs/locks.c
--- v2.1.36/linux/fs/locks.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/locks.c	Mon May 12 10:50:31 1997
@@ -100,6 +100,9 @@
  *
  *  Some adaptations for NFS support.
  *  Olaf Kirch (okir@monad.swb.de), Dec 1996,
+ *
+ *  Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
+ *  Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
  */
 
 #include <linux/malloc.h>
@@ -132,7 +135,7 @@
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
 static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx);
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx);
 
 static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);
 static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);
@@ -227,6 +230,7 @@
 posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
 {
 	locks_insert_block(blocker, waiter);
+	return;
 }
 
 void
@@ -234,6 +238,7 @@
 {
 	if (waiter->fl_prevblock)
 		locks_delete_block(waiter->fl_prevblock, waiter);
+	return;
 }
 
 /* Wake up processes blocked waiting for blocker.
@@ -269,20 +274,20 @@
 {
 	struct file_lock file_lock;
 	struct file *filp;
-	int err;
+	int error;
 
 	lock_kernel();
 	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		err = -EBADF;
+		error = -EBADF;
 	else if (!flock_make_lock(filp, &file_lock, cmd))
-		err = -EINVAL;
+		error = -EINVAL;
 	else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
-		err = -EBADF;
+		error = -EBADF;
 	else
-		err = flock_lock_file(filp, &file_lock,
-				      (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+		error = flock_lock_file(filp, &file_lock,
+					(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
 	unlock_kernel();
-	return err;
+	return (error);
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -298,7 +303,7 @@
 	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
 		return (-EBADF);
 	if (copy_from_user(&flock, l, sizeof(flock)))
-		return -EFAULT; 	
+		return (-EFAULT);
 
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
 		return (-EINVAL);
@@ -308,9 +313,9 @@
 
 	if (filp->f_op->lock) {
 		error = filp->f_op->lock(filp->f_inode, filp,
-					F_GETLK, &file_lock);
+					 F_GETLK, &file_lock);
 		if (error < 0)
-			return error;
+			return (error);
 		fl = &file_lock;
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
@@ -323,12 +328,12 @@
 			fl->fl_end - fl->fl_start + 1;
 		flock.l_whence = 0;
 		flock.l_type = fl->fl_type;
-		return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0; 
+		return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
 	} else {
 		flock.l_type = F_UNLCK;
   	}
   
-	return copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0; 
+	return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
 }
 
 /* Apply the lock described by l to an open file descriptor.
@@ -366,7 +371,7 @@
 	}
 
 	if (copy_from_user(&flock, l, sizeof(flock)))
-		return -EFAULT; 	
+		return (-EFAULT);
 	if (!posix_make_lock(filp, &file_lock, &flock))
 		return (-EINVAL);
 	
@@ -399,13 +404,13 @@
 		break;
 #endif
 	default:
-		return -EINVAL;
+		return (-EINVAL);
 	}
 
 	if (filp->f_op->lock != NULL) {
 		error = filp->f_op->lock(filp->f_inode, filp, cmd, &file_lock);
 		if (error < 0)
-			return error;
+			return (error);
 	}
 
 	return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
@@ -457,7 +462,7 @@
 			break;
 	}
 
-	return cfl;
+	return (cfl);
 }
 
 int locks_verify_locked(struct inode *inode)
@@ -1044,16 +1049,18 @@
 }
 
 
-static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
+static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
 {
+	static char temp[129];
+	char *p = temp;
 	struct inode *inode;
 
 	inode = fl->fl_file->f_inode;
 
 	p += sprintf(p, "%d:%s ", id, pfx);
 	if (fl->fl_flags & FL_POSIX) {
-		p += sprintf(p, "%s %s ",
-			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX",
+		p += sprintf(p, "%6s %s ",
+			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
 			     (IS_MANDLOCK(inode) &&
 			      (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
 			     "MANDATORY" : "ADVISORY ");
@@ -1066,28 +1073,68 @@
 		     fl->fl_pid,
 		     kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
 		     fl->fl_end);
-	p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
-		     (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
-		     (long)fl->fl_next, (long)fl->fl_nextblock);
-	return (p);
+	sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
+		(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
+		(long)fl->fl_next, (long)fl->fl_nextblock);
+	return (temp);
 }
 
-int get_locks_status(char *buf)
+static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
+				   off_t offset, int length)
+{
+	int i;
+
+	i = pos - offset;
+	if (i > 0) {
+		if (i >= length) {
+			i = len + length - i;
+			memcpy(*q, p, i);
+			*q += i;
+			return (0);
+		}
+		if (i < len) {
+			p += len - i;
+		}
+		else
+			i = len;
+		memcpy(*q, p, i);
+		*q += i;
+	}
+	
+	return (1);
+}
+
+int get_locks_status(char *buffer, char **start, off_t offset, int length)
 {
 	struct file_lock *fl;
 	struct file_lock *bfl;
 	char *p;
+	char *q = buffer;
 	int i;
+	int len;
+	off_t pos = 0;
 
-	p = buf;
 	for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
-		p = lock_get_status(fl, p, i, "");
+		p = lock_get_status(fl, i, "");
+		len = strlen(p);
+		pos += len;
+		if (!copy_lock_status(p, &q, pos, len, offset, length))
+			goto done;
 		if ((bfl = fl->fl_nextblock) == NULL)
 			continue;
 		do {
-			p = lock_get_status(bfl, p, i, " ->");
+			p = lock_get_status(bfl, i, " ->");
+			len = strlen(p);
+			pos += len;
+			if (!copy_lock_status(p, &q, pos, len, offset, length))
+				goto done;
 		} while ((bfl = bfl->fl_nextblock) != fl);
 	}
-	return (p - buf);
+done:
+	if (q != buffer)
+		*start = buffer;
+	return (q - buffer);
 }
+
+
 
diff -u --recursive --new-file v2.1.36/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v2.1.36/linux/fs/msdos/msdosfs_syms.c	Wed Apr 23 19:01:26 1997
+++ linux/fs/msdos/msdosfs_syms.c	Mon May 12 10:35:42 1997
@@ -30,7 +30,7 @@
 EXPORT_SYMBOL(msdos_put_super);
 
 
-static struct file_system_type msdos_fs_type = {
+struct file_system_type msdos_fs_type = {
 	msdos_read_super, "msdos", 1, NULL
 };
 
diff -u --recursive --new-file v2.1.36/linux/fs/namei.c linux/fs/namei.c
--- v2.1.36/linux/fs/namei.c	Thu Mar 27 14:40:06 1997
+++ linux/fs/namei.c	Mon May 12 10:35:42 1997
@@ -124,24 +124,16 @@
  * put_write_access() releases this write permission.
  * This is used for regular files.
  * We cannot support write (and maybe mmap read-write shared) accesses and
- * MAP_DENYWRITE mmappings simultaneously.
+ * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
+ * can have the following values:
+ * 0: no writers, no VM_DENYWRITE mappings
+ * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
+ * > 0: (i_writecount) users are writing to the file.
  */
 int get_write_access(struct inode * inode)
 {
-	struct task_struct * p;
-
-	if ((inode->i_count > 1) && S_ISREG(inode->i_mode)) /* shortcut */
-		for_each_task(p) {
-		        struct vm_area_struct * mpnt;
-			if (!p->mm)
-				continue;
-			for(mpnt = p->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
-				if (inode != mpnt->vm_inode)
-					continue;
-				if (mpnt->vm_flags & VM_DENYWRITE)
-					return -ETXTBSY;
-			}
-		}
+	if (inode->i_writecount < 0)
+		return -ETXTBSY;
 	inode->i_writecount++;
 	return 0;
 }
diff -u --recursive --new-file v2.1.36/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.36/linux/fs/ncpfs/inode.c	Wed Apr 23 19:01:26 1997
+++ linux/fs/ncpfs/inode.c	Mon May 12 10:35:42 1997
@@ -21,6 +21,7 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
+#include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
@@ -177,7 +178,7 @@
 		printk("ncp_read_super: could not alloc ncp_server\n");
 		return NULL;
 	}
-	ncp_filp->f_count += 1;
+	ncp_filp->f_count++;
 
 	lock_super(sb);
 
@@ -256,7 +257,7 @@
 	ncp_unlock_server(server);
 	ncp_kfree_s(server->packet, server->packet_size);
       fail:
-	ncp_filp->f_count -= 1;
+	put_filp(ncp_filp);
 	ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
 	return NULL;
 }
diff -u --recursive --new-file v2.1.36/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.36/linux/fs/nfs/write.c	Mon Apr 14 16:28:17 1997
+++ linux/fs/nfs/write.c	Mon May 12 17:39:50 1997
@@ -130,9 +130,9 @@
 
 #ifdef CONFIG_NFS_SWAP
 	/* async swap-out support */
-	if (clear_bit(PG_decr_after, &page->flags))
+	if (test_and_clear_bit(PG_decr_after, &page->flags))
 		atomic_dec(&page->count);
-	if (clear_bit(PG_swap_unlock_after, &page->flags))
+	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
 		swap_after_unlock_page(page->swap_unlock_entry);
 #endif
 }
@@ -530,7 +530,7 @@
 				page->offset);
 
 	req->wb_flags |= NFS_WRITE_WANTLOCK;
-	if (!set_bit(PG_locked, &page->flags)) {
+	if (!test_and_set_bit(PG_locked, &page->flags)) {
 		transfer_page_lock(req);
 	} else {
 		printk(KERN_WARNING "NFS oops in %s: can't lock page!\n",
@@ -719,7 +719,7 @@
 	if (!WB_HAVELOCK(req))
 		req->wb_flags |= NFS_WRITE_WANTLOCK;
 
-	if (WB_WANTLOCK(req) && set_bit(PG_locked, &page->flags)) {
+	if (WB_WANTLOCK(req) && test_and_set_bit(PG_locked, &page->flags)) {
 		dprintk("NFS:      page already locked in writeback_lock!\n");
 		task->tk_timeout = 2 * HZ;
 		rpc_sleep_on(&write_queue, task, NULL, NULL);
diff -u --recursive --new-file v2.1.36/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.36/linux/fs/nfsd/vfs.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/nfsd/vfs.c	Mon May 12 10:35:42 1997
@@ -285,6 +285,10 @@
 		if (err) {
 			if (wflag)
 				put_write_access(inode);
+
+			/* I nearly added put_filp() call here, but this filp
+			 * is really on callers stack frame. -DaveM
+			 */
 			filp->f_count--;
 			return nfserrno(-err);
 		}
diff -u --recursive --new-file v2.1.36/linux/fs/open.c linux/fs/open.c
--- v2.1.36/linux/fs/open.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/open.c	Mon May 12 10:35:42 1997
@@ -605,7 +605,7 @@
 cleanup_inode:
 	iput(inode);
 cleanup_file:
-	f->f_count--;
+	put_filp(f);
 	return error;
 }
 
diff -u --recursive --new-file v2.1.36/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.36/linux/fs/pipe.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/pipe.c	Mon May 12 10:35:42 1997
@@ -11,6 +11,7 @@
 #include <linux/fcntl.h>
 #include <linux/termios.h>
 #include <linux/mm.h>
+#include <linux/file.h>
 
 #include <asm/poll.h>
 #include <asm/uaccess.h>
@@ -74,7 +75,10 @@
 	PIPE_LOCK(*inode)--;
 	wake_up_interruptible(&PIPE_WAIT(*inode));
 	if (read) {
-	        inode->i_atime = CURRENT_TIME;
+		if (DO_UPDATE_ATIME(inode)) {
+			inode->i_atime = CURRENT_TIME;
+			inode->i_dirt = 1;
+		}
 		return read;
 	}
 	if (PIPE_WRITERS(*inode))
@@ -128,6 +132,7 @@
 		free = 1;
 	}
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	inode->i_dirt = 1;
 	return written;
 }
 
@@ -440,9 +445,9 @@
 	inode->i_count--;
 	iput(inode);
 close_f12:
-	f2->f_count--;
+	put_filp(f2);
 close_f1:
-	f1->f_count--;
+	put_filp(f1);
 no_files:
 	return error;	
 }
diff -u --recursive --new-file v2.1.36/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.36/linux/fs/proc/array.c	Mon Apr 14 16:28:18 1997
+++ linux/fs/proc/array.c	Mon May 12 10:50:31 1997
@@ -154,9 +154,7 @@
 	return read;
 }
 
-#ifdef __SMP__
 
-extern int setup_profiling_timer (unsigned int multiplier);
 
 /*
  * Writing to /proc/profile resets the counters
@@ -168,6 +166,8 @@
 	const char * buf, unsigned long count)
 {
 	int i=prof_len;
+#ifdef __SMP__
+	extern int setup_profiling_timer (unsigned int multiplier);
 
 	if (count==sizeof(int)) {
 		unsigned int multiplier;
@@ -178,14 +178,12 @@
 		if (setup_profiling_timer(multiplier))
 			return -EINVAL;
 	}
+#endif
   
 	while (i--)
 		prof_buffer[i]=0UL;
 	return count;
 }
-#else
-#define write_profile NULL
-#endif
 
 static struct file_operations proc_profile_operations = {
 	NULL,           /* lseek */
@@ -344,18 +342,6 @@
 	return sprintf(buffer, "%s\n", saved_command_line);
 }
 
-static struct task_struct ** get_task(pid_t pid)
-{
-	struct task_struct ** p;
-
-	p = task;
-	while (++p < task+NR_TASKS) {
-		if (*p && (*p)->pid == pid)
-			return p;
-	}
-	return NULL;
-}
-
 static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
 {
 	pgd_t *page_dir;
@@ -386,7 +372,7 @@
 	return pte_page(pte) + (ptr & ~PAGE_MASK);
 }
 
-static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
+static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
 {
 	unsigned long addr;
 	int size = 0, result = 0;
@@ -395,7 +381,7 @@
 	if (start >= end)
 		return result;
 	for (;;) {
-		addr = get_phys_addr(*p, start);
+		addr = get_phys_addr(p, start);
 		if (!addr)
 			return result;
 		do {
@@ -417,20 +403,20 @@
 
 static int get_env(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid);
+	struct task_struct *p = find_task_by_pid(pid);
 
-	if (!p || !*p || !(*p)->mm)
+	if (!p || !p->mm)
 		return 0;
-	return get_array(p, (*p)->mm->env_start, (*p)->mm->env_end, buffer);
+	return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
 }
 
 static int get_arg(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid);
+	struct task_struct *p = find_task_by_pid(pid);
 
-	if (!p || !*p || !(*p)->mm)
+	if (!p || !p->mm)
 		return 0;
-	return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
+	return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
 }
 
 static unsigned long get_wchan(struct task_struct *p)
@@ -443,7 +429,7 @@
 		unsigned long stack_page;
 		int count = 0;
 
-		stack_page = p->kernel_stack_page;
+		stack_page = 4096 + (unsigned long)p;
 		if (!stack_page)
 			return 0;
 		ebp = p->tss.ebp;
@@ -507,15 +493,16 @@
 }
 
 #if defined(__i386__)
-# define KSTK_EIP(tsk)	(((unsigned long *)tsk->kernel_stack_page)[1019])
-# define KSTK_ESP(tsk)	(((unsigned long *)tsk->kernel_stack_page)[1022])
+# define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
+# define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
 #elif defined(__alpha__)
   /*
    * See arch/alpha/kernel/ptrace.c for details.
    */
 # define PT_REG(reg)		(PAGE_SIZE - sizeof(struct pt_regs)	\
 				 + (long)&((struct pt_regs *)0)->reg)
-# define KSTK_EIP(tsk)	(*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
+# define KSTK_EIP(tsk) \
+    (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
 # define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
 #elif defined(__mc68000__)
 #define	KSTK_EIP(tsk)	\
@@ -681,9 +668,9 @@
 static int get_status(int pid, char * buffer)
 {
 	char * orig = buffer;
-	struct task_struct ** p = get_task(pid), *tsk;
+	struct task_struct *tsk = find_task_by_pid(pid);
 
-	if (!p || (tsk = *p) == NULL)
+	if (!tsk)
 		return 0;
 	buffer = task_name(tsk, buffer);
 	buffer = task_state(tsk, buffer);
@@ -694,14 +681,14 @@
 
 static int get_stat(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid), *tsk;
+	struct task_struct *tsk = find_task_by_pid(pid);
 	unsigned long sigignore=0, sigcatch=0, wchan;
 	unsigned long vsize, eip, esp;
 	long priority, nice;
 	int i,tty_pgrp;
 	char state;
 
-	if (!p || (tsk = *p) == NULL)
+	if (!tsk)
 		return 0;
 	if (tsk->state < 0 || tsk->state > 5)
 		state = '.';
@@ -714,10 +701,8 @@
 			vsize += vma->vm_end - vma->vm_start;
 			vma = vma->vm_next;
 		}
-		if (tsk->kernel_stack_page) {
-			eip = KSTK_EIP(tsk);
-			esp = KSTK_ESP(tsk);
-		}
+		eip = KSTK_EIP(tsk);
+		esp = KSTK_ESP(tsk);
 	}
 	wchan = get_wchan(tsk);
 	if (tsk->sig) {
@@ -864,10 +849,10 @@
 
 static int get_statm(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid), *tsk;
+	struct task_struct *tsk = find_task_by_pid(pid);
 	int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
 
-	if (!p || (tsk = *p) == NULL)
+	if (!tsk)
 		return 0;
 	if (tsk->mm && tsk->mm != &init_mm) {
 		struct vm_area_struct * vma = tsk->mm->mmap;
@@ -932,17 +917,17 @@
 static long read_maps (int pid, struct file * file,
 	char * buf, unsigned long count)
 {
-	struct task_struct ** p = get_task(pid);
+	struct task_struct *p = find_task_by_pid(pid);
 	char * destptr;
 	loff_t lineno;
 	int column;
 	struct vm_area_struct * map;
 	int i;
 
-	if (!p || !*p)
+	if (!p)
 		return -EINVAL;
 
-	if (!(*p)->mm || (*p)->mm == &init_mm || count == 0)
+	if (!p->mm || p->mm == &init_mm || count == 0)
 		return 0;
 
 	/* decode f_pos */
@@ -950,7 +935,7 @@
 	column = file->f_pos & (MAPS_LINE_LENGTH-1);
 
 	/* quickly go to line lineno */
-	for (map = (*p)->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+	for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
 		continue;
 
 	destptr = buf;
@@ -1011,7 +996,7 @@
 		/* By writing to user space, we might have slept.
 		 * Stop the loop, to avoid a race condition.
 		 */
-		if (*p != current)
+		if (p != current)
 			break;
 	}
 
@@ -1034,7 +1019,7 @@
 extern int get_pci_list(char*);
 extern int get_md_status (char *);
 extern int get_rtc_status (char *);
-extern int get_locks_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
 extern int get_swaparea_info (char *);
 #ifdef __SMP_PROF__
 extern int get_smp_prof_list(char *);
@@ -1121,7 +1106,7 @@
 			return get_rtc_status(page);
 #endif
 		case PROC_LOCKS:
-			return get_locks_status(page);
+			return get_locks_status(page, start, offset, length);
 #ifdef CONFIG_ZORRO
 		case PROC_ZORRO:
 			return zorro_get_list(page);
diff -u --recursive --new-file v2.1.36/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.1.36/linux/fs/proc/base.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/proc/base.c	Mon May 12 10:35:42 1997
@@ -52,17 +52,14 @@
 
 static void proc_pid_fill_inode(struct inode * inode)
 {
-	struct task_struct * p;
+	struct task_struct *p;
 	int pid = inode->i_ino >> 16;
 	int ino = inode->i_ino & 0xffff;
 
-	for_each_task(p) {
-		if (p->pid == pid) {
-			if (p->dumpable || ino == PROC_PID_INO) {
-				inode->i_uid = p->euid;
-				inode->i_gid = p->gid;
-			}
-			return;
+	if ((p = find_task_by_pid(pid)) != NULL) {
+		if (p->dumpable || ino == PROC_PID_INO) {
+			inode->i_uid = p->euid;
+			inode->i_gid = p->gid;
 		}
 	}
 }
diff -u --recursive --new-file v2.1.36/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.1.36/linux/fs/proc/fd.c	Thu Mar 27 14:40:06 1997
+++ linux/fs/proc/fd.c	Mon May 12 10:35:42 1997
@@ -58,7 +58,6 @@
 	unsigned int ino, pid, fd, c;
 	struct task_struct * p;
 	struct super_block * sb;
-	int i;
 
 	*result = NULL;
 	ino = dir->i_ino;
@@ -100,10 +99,8 @@
 			break;
 		}
 	}
-	for (i = 0 ; i < NR_TASKS ; i++)
-		if ((p = task[i]) && p->pid == pid)
-			break;
-	if (!pid || i >= NR_TASKS)
+	p = find_task_by_pid(pid);
+	if (!pid || !p)
 		return -ENOENT;
 
 	/*
@@ -112,8 +109,11 @@
 	 *	is NULL
 	 */
 
- 	if (fd >= NR_OPEN || !p->files || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
-	  return -ENOENT;
+ 	if (fd >= NR_OPEN	||
+	    !p->files		||
+	    !p->files->fd[fd]	||
+	    !p->files->fd[fd]->f_inode)
+		return -ENOENT;
 
 	ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
@@ -128,8 +128,7 @@
 	void * dirent, filldir_t filldir)
 {
 	char buf[NUMBUF];
-	int task_nr;
-	struct task_struct * p;
+	struct task_struct * p, **tarrayp;
 	unsigned int fd, pid, ino;
 	unsigned long i,j;
 
@@ -149,13 +148,10 @@
 			return 0;
 	}
 
-	task_nr = 1;
-	for (;;) {
-		if ((p = task[task_nr]) && p->pid == pid)
-			break;
-		if (++task_nr >= NR_TASKS)
-			return 0;
-	}
+	p = find_task_by_pid(pid);
+	if(!p)
+		return 0;
+	tarrayp = p->tarray_ptr;
 
 	for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
 		if (!p->files)
@@ -176,7 +172,7 @@
 			break;
 
 		/* filldir() might have slept, so we must re-validate "p" */
-		if (p != task[task_nr] || p->pid != pid)
+		if (p != *tarrayp || p->pid != pid)
 			break;
 	}
 	return 0;
diff -u --recursive --new-file v2.1.36/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.1.36/linux/fs/proc/inode.c	Mon Mar 17 14:54:30 1997
+++ linux/fs/proc/inode.c	Mon May 12 10:35:42 1997
@@ -81,7 +81,6 @@
 struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
 {
 	struct inode * inode = iget(s, ino);
-	struct task_struct *p;
 	
 #ifdef CONFIG_SUN_OPENPROMFS_MODULE
 	if ((inode->i_ino >= PROC_OPENPROM_FIRST)
@@ -111,9 +110,14 @@
 	 * Fixup the root inode's nlink value
 	 */
 	if (inode->i_ino == PROC_ROOT_INO) {
-		for_each_task(p)
-			if (p && p->pid)
+		struct task_struct *p;
+
+		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (p->pid)
 				inode->i_nlink++;
+		}
+		read_unlock(&tasklist_lock);
 	}
 	return inode;
 }			
@@ -155,7 +159,6 @@
 {
 	unsigned long ino, pid;
 	struct task_struct * p;
-	int i;
 	
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = 0;
@@ -170,13 +173,8 @@
 	inode->i_nlink = 1;
 	inode->i_size = 0;
 	pid = ino >> 16;
-	if (!pid)
-		return;
-	p = task[0];
-	for (i = 0; i < NR_TASKS ; i++)
-		if ((p = task[i]) && (p->pid == pid))
-			break;
-	if (!p || i >= NR_TASKS)
+
+	if (!pid || ((p = find_task_by_pid(pid)) == NULL))
 		return;
 
 	ino &= 0x0000ffff;
@@ -198,7 +196,6 @@
 				inode->i_mode |= S_IWUSR | S_IXUSR;
 			return;
 	}
-	return;
 }
 
 void proc_write_inode(struct inode * inode)
diff -u --recursive --new-file v2.1.36/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.1.36/linux/fs/proc/link.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/proc/link.c	Mon May 12 10:35:42 1997
@@ -68,7 +68,7 @@
 	unsigned int pid, ino;
 	struct task_struct * p;
 	struct inode * new_inode;
-	int i, error;
+	int error;
 
 	*res_inode = NULL;
 	if (dir)
@@ -82,10 +82,9 @@
 	ino = inode->i_ino;
 	pid = ino >> 16;
 	ino &= 0x0000ffff;
-	for (i = 0 ; i < NR_TASKS ; i++)
-		if ((p = task[i]) && p->pid == pid)
-			break;
-	if (i >= NR_TASKS) {
+
+	p = find_task_by_pid(pid);
+	if (!p) {
 		iput(inode);
 		return -ENOENT;
 	}
diff -u --recursive --new-file v2.1.36/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.1.36/linux/fs/proc/mem.c	Mon Apr 14 16:28:18 1997
+++ linux/fs/proc/mem.c	Mon May 12 17:39:50 1997
@@ -55,16 +55,10 @@
 	struct task_struct * tsk = current;
 
 	if (pid != tsk->pid) {
-		int i;
-		tsk = NULL;
-		for (i = 1 ; i < NR_TASKS ; i++)
-			if (task[i] && task[i]->pid == pid) {
-				tsk = task[i];
-				break;
-			}
-		/*
-		 * allow accesses only under the same circumstances
-		 * that we would allow ptrace to work
+		tsk = find_task_by_pid(pid);
+
+		/* Allow accesses only under the same circumstances
+		 * that we would allow ptrace to work.
 		 */
 		if (tsk) {
 			if (!(tsk->flags & PF_PTRACED)
@@ -291,10 +285,10 @@
 			return -ENOMEM;
 
 		if (!pte_present(*src_table))
-			do_no_page(tsk, src_vma, stmp, 1);
+			handle_mm_fault(src_vma, stmp, 1);
 
 		if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
-			do_wp_page(tsk, src_vma, stmp, 1);
+			handle_mm_fault(src_vma, stmp, 1);
 
 		set_pte(src_table, pte_mkdirty(*src_table));
 		set_pte(dest_table, *src_table);
diff -u --recursive --new-file v2.1.36/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.36/linux/fs/proc/root.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/proc/root.c	Mon May 12 10:35:42 1997
@@ -683,16 +683,20 @@
 	struct inode ** result)
 {
 	unsigned int pid, c;
-	int i, ino, retval;
+	int ino, retval;
 	struct task_struct *p;
 
 	dir->i_count++;
 
 	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
 		dir->i_nlink = proc_root.nlink;
-		for_each_task(p)
-			if (p && p->pid)
+
+		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (p->pid)
 				dir->i_nlink++;
+		}
+		read_unlock(&tasklist_lock);
 	}
 
 	retval = proc_lookup(dir, name, len, result);
@@ -716,10 +720,8 @@
 			break;
 		}
 	}
-	for (i = 0 ; i < NR_TASKS ; i++)
-		if (task[i] && task[i]->pid == pid)
-			break;
-	if (!pid || i >= NR_TASKS) {
+	p = find_task_by_pid(pid);
+	if (!pid || !p) {
 		iput(dir);
 		return -ENOENT;
 	}
@@ -796,34 +798,40 @@
 static int proc_root_readdir(struct inode * inode, struct file * filp,
 	void * dirent, filldir_t filldir)
 {
+	struct task_struct *p;
 	char buf[NUMBUF];
-	unsigned int nr,pid;
-	unsigned long i,j;
+	unsigned int nr = filp->f_pos;
 
-	nr = filp->f_pos;
 	if (nr < FIRST_PROCESS_ENTRY) {
 		int error = proc_readdir(inode, filp, dirent, filldir);
 		if (error <= 0)
 			return error;
-		filp->f_pos = nr = FIRST_PROCESS_ENTRY;
+		filp->f_pos = FIRST_PROCESS_ENTRY;
 	}
+	nr = FIRST_PROCESS_ENTRY;
 
-	for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
-		struct task_struct * p = task[nr];
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		unsigned int pid;
 
-		if (!p || !(pid = p->pid))
+		if(nr++ < filp->f_pos)
 			continue;
 
-		j = NUMBUF;
-		i = pid;
-		do {
-			j--;
-			buf[j] = '0' + (i % 10);
-			i /= 10;
-		} while (i);
+		if((pid = p->pid) != 0) {
+			unsigned long j = NUMBUF, i = pid;
 
-		if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
-			break;
+			do {
+				j--;
+				buf[j] = '0' + (i % 10);
+				i /= 10;
+			} while (i);
+
+			if (filldir(dirent, buf+j, NUMBUF-j,
+				    filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
+				break;
+		}
+		filp->f_pos++;
 	}
+	read_unlock(&tasklist_lock);
 	return 0;
 }
diff -u --recursive --new-file v2.1.36/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.36/linux/fs/smbfs/inode.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/smbfs/inode.c	Mon May 12 10:35:42 1997
@@ -17,6 +17,7 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
+#include <linux/file.h>
 #include <linux/fcntl.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
@@ -242,7 +243,7 @@
 		printk("smb_read_super: could not alloc smb_sb_info\n");
 		return NULL;
 	}
-	filp->f_count += 1;
+	filp->f_count++;
 
 	lock_super(sb);
 
@@ -319,7 +320,7 @@
 		smb_vfree(server->packet);
 		server->packet = NULL;
 	}
-	filp->f_count -= 1;
+	put_filp(filp);
 	smb_dont_catch_keepalive(server);
 	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
 	return NULL;
diff -u --recursive --new-file v2.1.36/linux/fs/super.c linux/fs/super.c
--- v2.1.36/linux/fs/super.c	Mon Apr 14 16:28:18 1997
+++ linux/fs/super.c	Mon May 12 10:35:43 1997
@@ -33,6 +33,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/fd.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -552,7 +553,7 @@
 	int i;
 
 	for (i = 1; i < 256; i++) {
-		if (!set_bit(i,unnamed_dev_in_use))
+		if (!test_and_set_bit(i,unnamed_dev_in_use))
 			return MKDEV(UNNAMED_MAJOR, i);
 	}
 	return 0;
@@ -562,7 +563,7 @@
 {
 	if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
 		return;
-	if (clear_bit(MINOR(dev), unnamed_dev_in_use))
+	if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
 		return;
 	printk("VFS: put_unnamed_dev: freeing unused device %s\n",
 			kdevname(dev));
@@ -937,7 +938,11 @@
 	return retval;
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
 static void do_mount_root(void)
+#else
+__initfunc(static void do_mount_root(void))
+#endif
 {
 	struct file_system_type * fs_type;
 	struct super_block * sb;
@@ -1046,7 +1051,7 @@
 }
 
 
-void mount_root(void)
+__initfunc(void mount_root(void))
 {
 	memset(super_blocks, 0, sizeof(super_blocks));
 	do_mount_root();
diff -u --recursive --new-file v2.1.36/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.36/linux/fs/umsdos/namei.c	Sat Nov 30 02:24:02 1996
+++ linux/fs/umsdos/namei.c	Mon May 12 10:35:43 1997
@@ -301,6 +301,9 @@
 		,*(unsigned long *)current->kernel_stack_page \
 		,__LINE__); \
 	}
+
+#undef chkstk
+#define chkstk() do { } while (0)
 	
 /*
 	Rename a file (move) in the file system.
diff -u --recursive --new-file v2.1.36/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.36/linux/fs/vfat/namei.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/vfat/namei.c	Mon May 12 10:35:43 1997
@@ -174,10 +174,12 @@
 		printk("------- vfat kstack ok in %s line %d: SL=%d\n",
 		       fname, lineno, stack_level);
 #endif
+#if 0
 	if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
 		printk("******* vfat stack corruption detected in %s at line %d\n",
 		       fname, lineno);
 	}
+#endif
 }
 
 static int debug = 0;
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- v2.1.36/linux/include/asm-alpha/atomic.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-alpha/atomic.h	Mon May 12 10:35:43 1997
@@ -41,9 +41,9 @@
 	"	addl %0,%2,%0\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
 	:"Ir" (i), "m" (__atomic_fool_gcc(v)));
 }
@@ -56,9 +56,9 @@
 	"	subl %0,%2,%0\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
 	:"Ir" (i), "m" (__atomic_fool_gcc(v)));
 }
@@ -75,9 +75,9 @@
 	"	mov %0,%2\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
 	:"Ir" (i), "m" (__atomic_fool_gcc(v)));
 	return result;
@@ -92,9 +92,9 @@
 	"	mov %0,%2\n"
 	"	stl_c %0,%1\n"
 	"	beq %0,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
 	:"Ir" (i), "m" (__atomic_fool_gcc(v)));
 	return result;
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.1.36/linux/include/asm-alpha/bitops.h	Fri Apr  4 08:52:24 1997
+++ linux/include/asm-alpha/bitops.h	Mon May 12 10:35:43 1997
@@ -17,7 +17,7 @@
  * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1).
  */
 
-extern __inline__ unsigned long set_bit(unsigned long nr, void * addr)
+extern __inline__ void set_bit(unsigned long nr, void * addr)
 {
 	unsigned long oldbit;
 	unsigned long temp;
@@ -31,16 +31,75 @@
 	"	stl_c %0,%1\n"
 	"	beq %0,3f\n"
 	"2:\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
-	".text"
+	".previous"
+	:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
+	:"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ void clear_bit(unsigned long nr, void * addr)
+{
+	unsigned long oldbit;
+	unsigned long temp;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%1\n"
+	"	and %0,%3,%2\n\t"
+	"	beq %2,2f\n\t"
+	"	xor %0,%3,%0\n\t"
+	"	stl_c %0,%1\n\t"
+	"	beq %0,3f\n"
+	"2:\n"
+	".section .text2,\"ax\"\n"
+	"3:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
+	:"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ void change_bit(unsigned long nr, void * addr)
+{
+	unsigned long temp;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%1\n"
+	"	xor %0,%2,%0\n\t"
+	"	stl_c %0,%1\n\t"
+	"	beq %0,3f\n"
+	".section .text2,\"ax\"\n"
+	"3:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (*m)
+	:"Ir" (1UL << (nr & 31)), "m" (*m));
+}
+
+extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void * addr)
+{
+	unsigned long oldbit;
+	unsigned long temp;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%1\n"
+	"	and %0,%3,%2\n"
+	"	bne %2,2f\n"
+	"	xor %0,%3,%0\n"
+	"	stl_c %0,%1\n"
+	"	beq %0,3f\n"
+	"2:\n"
+	".section .text2,\"ax\"\n"
+	"3:	br 1b\n"
+	".previous"
 	:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
 	:"Ir" (1UL << (nr & 31)), "m" (*m));
 
 	return oldbit != 0;
 }
 
-extern __inline__ unsigned long clear_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void * addr)
 {
 	unsigned long oldbit;
 	unsigned long temp;
@@ -54,16 +113,16 @@
 	"	stl_c %0,%1\n\t"
 	"	beq %0,3f\n"
 	"2:\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
 	:"Ir" (1UL << (nr & 31)), "m" (*m));
 
 	return oldbit != 0;
 }
 
-extern __inline__ unsigned long change_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void * addr)
 {
 	unsigned long oldbit;
 	unsigned long temp;
@@ -75,9 +134,9 @@
 	"	xor %0,%3,%0\n\t"
 	"	stl_c %0,%1\n\t"
 	"	beq %0,3f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"3:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
 	:"Ir" (1UL << (nr & 31)), "m" (*m));
 
@@ -166,15 +225,15 @@
 
 #ifdef __KERNEL__
 
-#define ext2_set_bit                 set_bit
-#define ext2_clear_bit               clear_bit
+#define ext2_set_bit                 test_and_set_bit
+#define ext2_clear_bit               test_and_clear_bit
 #define ext2_test_bit                test_bit
 #define ext2_find_first_zero_bit     find_first_zero_bit
 #define ext2_find_next_zero_bit      find_next_zero_bit
 
 /* Bitmap functions for the minix filesystem.  */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
 #define minix_test_bit(nr,addr) test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/current.h linux/include/asm-alpha/current.h
--- v2.1.36/linux/include/asm-alpha/current.h	Thu Feb  6 04:42:35 1997
+++ linux/include/asm-alpha/current.h	Mon May 12 10:35:43 1997
@@ -1,12 +1,6 @@
 #ifndef _ALPHA_CURRENT_H
 #define _ALPHA_CURRENT_H
 
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.
- */
-extern struct task_struct *current_set[NR_CPUS];
-
 register struct task_struct *current __asm__("$8");
 
 #endif /* !(_ALPHA_CURRENT_H) */
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.1.36/linux/include/asm-alpha/io.h	Mon Apr 14 16:28:18 1997
+++ linux/include/asm-alpha/io.h	Mon May 12 10:35:43 1997
@@ -39,7 +39,7 @@
 extern inline void set_hae(unsigned long new_hae)
 {
 	unsigned long ipl;
-	swpipl(ipl,7);
+	ipl = swpipl(7);
 	hae.cache = new_hae;
 	*hae.reg = new_hae;
 	mb();
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.1.36/linux/include/asm-alpha/processor.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-alpha/processor.h	Mon May 12 10:35:43 1997
@@ -49,7 +49,7 @@
 };
 
 #define INIT_MMAP { &init_mm, 0xfffffc0000000000,  0xfffffc0010000000, \
-	PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+	PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
 	0, 0, 0, \
@@ -85,10 +85,12 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
-#define free_task_struct(p)	kfree(p)
-#define free_kernel_stack(page) free_page((page))
+/* NOTE: The task struct and the stack go together!  */
+#define alloc_task_struct() \
+        ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p)     free_pages((unsigned long)(p),1)
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
 
 #endif /* __ASM_ALPHA_PROCESSOR_H */
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.1.36/linux/include/asm-alpha/semaphore.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-alpha/semaphore.h	Mon May 12 10:35:43 1997
@@ -47,9 +47,9 @@
 	"	stl_c	%0,%2\n"
 	"	beq	%0,3f\n"
 	"2:\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"3:	br	1b\n"
-	".text"
+	".previous"
 	: "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
 	: "0"(0));
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.1.36/linux/include/asm-alpha/softirq.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-alpha/softirq.h	Mon May 12 10:35:43 1997
@@ -17,9 +17,9 @@
 	"	and %0,%2,%0\n"
 	"	stq_c %0,%1\n"
 	"	beq %0,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	:"=&r" (temp), "=m" (bh_active)
 	:"Ir" (x), "m" (bh_active));
 }
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.1.36/linux/include/asm-alpha/spinlock.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-alpha/spinlock.h	Mon May 12 17:39:50 1997
@@ -3,8 +3,9 @@
 
 #ifndef __SMP__
 
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+/* gcc 2.7.2 can crash initializing an empty structure.  */
+typedef struct { int dummy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0 }
 
 #define spin_lock_init(lock)			do { } while(0)
 #define spin_lock(lock)				do { } while(0)
@@ -14,7 +15,7 @@
 #define spin_lock_irq(lock)			setipl(7)
 #define spin_unlock_irq(lock)			setipl(0)
 
-#define spin_lock_irqsave(lock, flags)		swpipl(flags,7)
+#define spin_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
 #define spin_unlock_irqrestore(lock, flags)	setipl(flags)
 
 /*
@@ -27,8 +28,8 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef struct { int dummy; } rwlock_t;
+#define RW_LOCK_UNLOCKED { 0 }
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
@@ -39,10 +40,10 @@
 #define write_lock_irq(lock)	cli()
 #define write_unlock_irq(lock)	sti()
 
-#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
+#define read_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
+#define read_unlock_irqrestore(lock, flags)	setipl(flags)
+#define write_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
+#define write_unlock_irqrestore(lock, flags)	setipl(flags)
 
 #else
 
@@ -89,13 +90,13 @@
 	"	stq_c	%0,%1\n"
 	"	beq	%0,3f\n"
 	"4:	mb\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	ldq	%0,%1\n"
 	"	subq	%2,1,%2\n"
 	"3:	blt	%2,4b\n"
 	"	blbs	%0,2b\n"
 	"	br	1b\n"
-	".text"
+	".previous"
 	: "=r" (tmp),
 	  "=m" (__dummy_lock(lock)),
 	  "=r" (stuck)
@@ -107,7 +108,7 @@
 		lock->previous = (unsigned long) &&l1;
 }
 
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
 #define spin_lock_irq(lock) \
 	do { __cli(); spin_lock(lock); } while (0)
@@ -116,7 +117,7 @@
 	do { spin_unlock(lock); __sti(); } while (0)
 
 #define spin_lock_irqsave(lock, flags) \
-	do { swpipl(flags,7); spin_lock(lock); } while (0)
+	do { flags = swpipl(7); spin_lock(lock); } while (0)
 
 #define spin_unlock_irqrestore(lock, flags) \
 	do { spin_unlock(lock); setipl(flags); } while (0)
diff -u --recursive --new-file v2.1.36/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.1.36/linux/include/asm-alpha/system.h	Fri Apr  4 08:52:25 1997
+++ linux/include/asm-alpha/system.h	Mon May 12 10:35:43 1997
@@ -56,63 +56,95 @@
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
 #define switch_to(prev,next) do { \
-	current_set[0] = current = next; \
+	current = next; \
 	alpha_switch_to((unsigned long) &current->tss - 0xfffffc0000000000); \
 } while (0)
 
 extern void alpha_switch_to(unsigned long pctxp);
 
-extern void imb(void);
-
 #define mb() \
 __asm__ __volatile__("mb": : :"memory")
 
+#define imb() \
+__asm__ __volatile__ ("call_pal %0" : : "i" (PAL_imb) : "memory")
+
 #define draina() \
 __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_draina) : "memory")
 
-#define getipl(__old_ipl) \
-__asm__ __volatile__( \
-	"call_pal 54\n\t" \
-	"bis $0,$0,%0" \
-	: "=r" (__old_ipl) \
-	: : "$0", "$1", "$16", "$22", "$23", "$24", "$25")
-
-#define setipl(__new_ipl) \
-__asm__ __volatile__( \
-	"bis %0,%0,$16\n\t" \
-	"call_pal 53" \
-	: : "r" (__new_ipl) \
-	: "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory")
-
-#define swpipl(__old_ipl,__new_ipl) \
-__asm__ __volatile__( \
-	"bis %1,%1,$16\n\t" \
-	"call_pal 53\n\t" \
-	"bis $0,$0,%0" \
-	: "=r" (__old_ipl) \
-	: "r" (__new_ipl) \
-	: "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory")
+#define call_pal1(palno,arg) \
+({ \
+	register unsigned long __r0 __asm__("$0"); \
+	register unsigned long __r16 __asm__("$16"); __r16 = arg; \
+	__asm__ __volatile__( \
+		"call_pal %3" \
+		:"=r" (__r0),"=r" (__r16) \
+		:"1" (__r16),"i" (palno) \
+		:"$1", "$22", "$23", "$24", "$25", "memory"); \
+	__r0; \
+})
+
+#define getipl() \
+({ \
+	register unsigned long r0 __asm__("$0"); \
+	__asm__ __volatile__( \
+		"call_pal %1" \
+		:"=r" (r0) \
+		:"i" (PAL_rdps) \
+		:"$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
+	r0; \
+})
+
+#define setipl(ipl) \
+do { \
+	register unsigned long __r16 __asm__("$16") = (ipl); \
+	__asm__ __volatile__( \
+		"call_pal %2" \
+		:"=r" (__r16) \
+		:"0" (__r16),"i" (PAL_swpipl) \
+		:"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
+} while (0)
+
+#define swpipl(ipl) \
+({ \
+	register unsigned long __r0 __asm__("$0"); \
+	register unsigned long __r16 __asm__("$16") = (ipl); \
+	__asm__ __volatile__( \
+		"call_pal %3" \
+		:"=r" (__r0),"=r" (__r16) \
+		:"1" (__r16),"i" (PAL_swpipl) \
+		:"$1", "$22", "$23", "$24", "$25", "memory"); \
+	__r0; \
+})
 
 #define __cli()			setipl(7)
 #define __sti()			setipl(0)
-#define __save_flags(flags)	getipl(flags)
+#define __save_flags(flags)	do { (flags) = getipl(); } while (0)
 #define __restore_flags(flags)	setipl(flags)
 
 #define cli()			setipl(7)
 #define sti()			setipl(0)
-#define save_flags(flags)	getipl(flags)
+#define save_flags(flags)	do { (flags) = getipl(); } while (0)
 #define restore_flags(flags)	setipl(flags)
 
 /*
  * TB routines..
  */
-extern void tbi(long type, ...);
+#define __tbi(nr,arg,arg1...) do { \
+	register unsigned long __r16 __asm__("$16") = (nr); \
+	register unsigned long __r17 __asm__("$17"); arg; \
+	__asm__ __volatile__( \
+		"call_pal %3" \
+		:"=r" (__r16),"=r" (__r17) \
+		:"0" (__r16),"i" (PAL_tbi) ,##arg1 \
+		:"$0", "$1", "$22", "$23", "$24", "$25"); \
+} while (0)
 
-#define tbisi(x)	tbi(1,(x))
-#define tbisd(x)	tbi(2,(x))
-#define tbis(x)		tbi(3,(x))
-#define tbiap()		tbi(-1)
-#define tbia()		tbi(-2)
+#define tbi(x,y)	__tbi(x,__r17=(y),"1" (__r17))
+#define tbisi(x)	__tbi(1,__r17=(x),"1" (__r17))
+#define tbisd(x)	__tbi(2,__r17=(x),"1" (__r17))
+#define tbis(x)		__tbi(3,__r17=(x),"1" (__r17))
+#define tbiap()		__tbi(-1, /* no second argument */)
+#define tbia()		__tbi(-2, /* no second argument */)
 
 /*
  * Give prototypes to shut up gcc.
@@ -129,9 +161,9 @@
 	"	bis %3,%3,%1\n"
 	"	stl_c %1,%2\n"
 	"	beq %1,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	: "=&r" (val), "=&r" (dummy), "=m" (*m)
 	: "r" (val), "m" (*m));
 
@@ -147,9 +179,9 @@
 	"	bis %3,%3,%1\n"
 	"	stq_c %1,%2\n"
 	"	beq %1,2f\n"
-	".text 2\n"
+	".section .text2,\"ax\"\n"
 	"2:	br 1b\n"
-	".text"
+	".previous"
 	: "=&r" (val), "=&r" (dummy), "=m" (*m)
 	: "r" (val), "m" (*m));
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.1.36/linux/include/asm-i386/bitops.h	Mon Apr  7 11:35:31 1997
+++ linux/include/asm-i386/bitops.h	Mon May 12 10:35:43 1997
@@ -26,7 +26,31 @@
 #define ADDR (*(struct __dummy *) addr)
 #define CONST_ADDR (*(const struct __dummy *) addr)
 
-extern __inline__ int set_bit(int nr, volatile void * addr)
+extern __inline__ void set_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btsl %1,%0"
+		:"=m" (ADDR)
+		:"ir" (nr));
+}
+
+extern __inline__ void clear_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btrl %1,%0"
+		:"=m" (ADDR)
+		:"ir" (nr));
+}
+
+extern __inline__ void change_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__( LOCK_PREFIX
+		"btcl %1,%0"
+		:"=m" (ADDR)
+		:"ir" (nr));
+}
+
+extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
 	int oldbit;
 
@@ -37,7 +61,7 @@
 	return oldbit;
 }
 
-extern __inline__ int clear_bit(int nr, volatile void * addr)
+extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
 	int oldbit;
 
@@ -48,7 +72,7 @@
 	return oldbit;
 }
 
-extern __inline__ int change_bit(int nr, volatile void * addr)
+extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
 	int oldbit;
 
@@ -150,15 +174,15 @@
 
 #ifdef __KERNEL__
 
-#define ext2_set_bit                 set_bit
-#define ext2_clear_bit               clear_bit
+#define ext2_set_bit                 test_and_set_bit
+#define ext2_clear_bit               test_and_clear_bit
 #define ext2_test_bit                test_bit
 #define ext2_find_first_zero_bit     find_first_zero_bit
 #define ext2_find_next_zero_bit      find_next_zero_bit
 
 /* Bitmap functions for the minix filesystem.  */
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
 #define minix_test_bit(nr,addr) test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/current.h linux/include/asm-i386/current.h
--- v2.1.36/linux/include/asm-i386/current.h	Mon Dec 30 01:58:34 1996
+++ linux/include/asm-i386/current.h	Mon May 12 10:35:43 1997
@@ -1,12 +1,14 @@
 #ifndef _I386_CURRENT_H
 #define _I386_CURRENT_H
 
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.  For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()])	/* Current on this processor */
+static inline unsigned long get_esp(void)
+{
+	unsigned long esp;
+	__asm__("movl %%esp,%0":"=r" (esp));
+	return esp;
+}
+
+#define current ((struct task_struct *)(get_esp() & ~8191UL))
+
 
 #endif /* !(_I386_CURRENT_H) */
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/delay.h linux/include/asm-i386/delay.h
--- v2.1.36/linux/include/asm-i386/delay.h	Sun Jan 26 05:36:05 1997
+++ linux/include/asm-i386/delay.h	Mon May 12 10:35:43 1997
@@ -30,20 +30,25 @@
  * first constant multiplications gets optimized away if the delay is
  * a constant)
  */
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
 	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
 	__asm__("mull %0"
 		:"=d" (usecs)
-#ifdef __SMP__
-		:"a" (usecs),"0" (cpu_data[smp_processor_id()].udelay_val)
-#else
-		:"a" (usecs),"0" (loops_per_sec)
-#endif
+		:"a" (usecs),"0" (lps)
 		:"ax");
 		
 	__delay(usecs);
 }
+
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
+
 
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.1.36/linux/include/asm-i386/hardirq.h	Mon Apr 14 16:28:18 1997
+++ linux/include/asm-i386/hardirq.h	Tue May 13 21:37:06 1997
@@ -58,7 +58,6 @@
 		return 0;
 	}
 	++local_irq_count[cpu];
-	__sti();
 	return 1;
 }
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.36/linux/include/asm-i386/processor.h	Sun Jan 26 02:07:46 1997
+++ linux/include/asm-i386/processor.h	Mon May 12 10:35:43 1997
@@ -119,14 +119,15 @@
 /* virtual 86 mode info */
 	struct vm86_struct * vm86_info;
 	unsigned long screen_bitmap;
-	unsigned long v86flags, v86mask, v86mode;
+	unsigned long v86flags, v86mask, v86mode, saved_esp0;
 };
 
-#define INIT_MMAP { &init_mm, 0xC0000000, 0xFFFFF000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP \
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
 	0,0, \
-	sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
+	sizeof(init_stack) + (long) &init_stack, \
 	KERNEL_DS, 0, \
 	0,0,0,0,0,0, \
 	(long) &swapper_pg_dir - PAGE_OFFSET, \
@@ -137,7 +138,7 @@
 	{~0, }, /* ioperm */ \
 	_TSS(0), 0, 0, 0, KERNEL_DS, \
 	{ { 0, }, },  /* 387 state */ \
-	NULL, 0, 0, 0, 0 /* vm86_info */, \
+	NULL, 0, 0, 0, 0, 0 /* vm86_info */, \
 }
 
 #define start_thread(regs, new_eip, new_esp) do {\
@@ -164,9 +165,14 @@
 }
 
 /* Allocation and freeing of basic task resources. */
-#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
-#define free_task_struct(p)	kfree(p)
-#define free_kernel_stack(page) free_page((page))
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p)	free_pages((unsigned long)(p),1)
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
 
 #endif /* __ASM_I386_PROCESSOR_H */
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.1.36/linux/include/asm-i386/semaphore.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-i386/semaphore.h	Mon May 12 17:39:50 1997
@@ -81,48 +81,28 @@
  * "down_failed" is a special asm handler that calls the C
  * routine that actually waits. See arch/i386/lib/semaphore.S
  */
-extern inline void down(struct semaphore * sem)
+extern inline void do_down(struct semaphore * sem, void (*failed)(void))
 {
 	__asm__ __volatile__(
 		"# atomic down operation\n\t"
-		"movl $1f,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
 		"decl 0(%0)\n\t"
-		"js " SYMBOL_NAME_STR(__down_failed)
-		"\n1:"
+		"js 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tpushl $1b\n\t"
+		"jmp %1\n"
+		".previous"
 		:/* no outputs */
-		:"c" (sem)
-		:"ax","memory");
-}
-
-/*
- * This version waits in interruptible state so that the waiting
- * process can be killed.  The down_failed_interruptible routine
- * returns negative for signalled and zero for semaphore acquired.
- */
-extern inline int down_interruptible(struct semaphore * sem)
-{
-	int	ret;
-
-	__asm__ __volatile__(
-		"# atomic interruptible down operation\n\t"
-		"movl $1f,%0\n\t"
-#ifdef __SMP__
-		"lock ; "
-#endif
-		"decl 0(%1)\n\t"
-		"js " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
-		"xorl %0,%0"
-		"\n1:"
-		:"=a" (ret)
-		:"c" (sem)
+		:"c" (sem), "m" (*(unsigned long *)failed)
 		:"memory");
-
-	return ret;
 }
 
+#define down(sem) do_down((sem),__down_failed)
+#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
+
 /*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
@@ -133,16 +113,19 @@
 {
 	__asm__ __volatile__(
 		"# atomic up operation\n\t"
-		"movl $1f,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
 		"incl 0(%0)\n\t"
-		"jle " SYMBOL_NAME_STR(__up_wakeup)
-		"\n1:"
+		"jle 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		"2:\tpushl $1b\n\t"
+		"jmp %1\n"
+		".previous"
 		:/* no outputs */
-		:"c" (sem)
-		:"ax", "memory");
+		:"c" (sem), "m" (*(unsigned long *)__up_wakeup)
+		:"memory");
 }
 
 #endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.1.36/linux/include/asm-i386/smp.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-i386/smp.h	Mon May 12 10:35:43 1997
@@ -178,7 +178,6 @@
 extern int smp_scan_config(unsigned long, unsigned long);
 extern unsigned long smp_alloc_memory(unsigned long mem_base);
 extern unsigned char *apic_reg;
-extern unsigned char *kernel_stacks[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
 extern volatile int cpu_number_map[NR_CPUS];
@@ -192,6 +191,9 @@
 extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
 extern unsigned long ipi_count;
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
+extern void smp_local_timer_interrupt(struct pt_regs * regs);
+extern void setup_APIC_clock (void);
+
 
 /*
  *	General functions that each host system must provide.
@@ -228,7 +230,9 @@
  *	the apic we get the right answer). Hopefully other processors are more sensible 8)
  */
 
-extern __inline int smp_processor_id(void)
+#define smp_processor_id() (current->processor)
+
+extern __inline int hard_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_ID(*(unsigned long *)(apic_reg+APIC_ID));
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h
--- v2.1.36/linux/include/asm-i386/smp_lock.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-i386/smp_lock.h	Tue May 13 21:57:53 1997
@@ -31,14 +31,11 @@
 #define reacquire_kernel_lock(task, cpu, depth) \
 do { if (depth) __asm__ __volatile__( \
 	"cli\n\t" \
-	"movl $0f,%%eax\n\t" \
-	"jmp __lock_kernel\n" \
-	"0:\t" \
+	"call __lock_kernel\n\t" \
 	"movl %2,%0\n\t" \
 	"sti" \
 	: "=m" (task->lock_depth) \
-	: "d" (cpu), "c" (depth) \
-	: "ax"); \
+	: "d" (cpu), "c" (depth)); \
 } while (0)
 	
 
@@ -62,14 +59,12 @@
 	cli
 	cmpl	$0, %0
 	jne	0f
-	movl	$0f, %%eax
-	jmp	__lock_kernel
-0:
-	incl	%0
+	call	__lock_kernel
+0:	incl	%0
 	popfl
 "	:
-	: "m" (current_set[cpu]->lock_depth), "d" (cpu)
-	: "ax", "memory");
+	: "m" (current->lock_depth), "d" (cpu)
+	: "memory");
 }
 
 extern __inline__ void unlock_kernel(void)
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h
--- v2.1.36/linux/include/asm-i386/spinlock.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-i386/spinlock.h	Mon May 12 17:39:50 1997
@@ -77,13 +77,15 @@
 
 #define spin_lock(lock) \
 __asm__ __volatile__( \
-	"jmp 2f\n" \
-	"1:\t" \
-	"testb $1,%0\n\t" \
-	"jne 1b\n" \
-	"2:\t" \
+	"\n1:\t" \
 	"lock ; btsl $0,%0\n\t" \
-	"jc 1b" \
+	"jc 2f\n" \
+	".section .text.lock,\"ax\"\n" \
+	"2:\t" \
+	"testb $1,%0\n\t" \
+	"jne 2b\n\t" \
+	"jmp 1b\n" \
+	".previous" \
 	:"=m" (__dummy_lock(lock)))
 
 #define spin_unlock(lock) \
@@ -91,33 +93,7 @@
 	"lock ; btrl $0,%0" \
 	:"=m" (__dummy_lock(lock)))
 
-#undef spin_lock
-static inline void spin_lock(spinlock_t * lock)
-{
-	__label__ l1;
-	int stuck = 10000000;
-l1:
-	__asm__ __volatile__(
-		"jmp 2f\n"
-		"1:\t"
-		"decl %1\n\t"
-		"je 3f\n\t"
-		"testb $1,%0\n\t"
-		"jne 1b\n"
-		"2:\t"
-		"lock ; btsl $0,%0\n\t"
-		"jc 1b\n"
-		"3:"
-		:"=m" (__dummy_lock(lock)),
-		 "=r" (stuck)
-		:"1" (stuck));
-	if (!stuck) {
-		printk("spinlock stuck at %p (%lx)\n",&&l1,lock->previous);
-	} else
-		lock->previous = (unsigned long) &&l1;
-}
-
-#define spin_trylock(lock) (!set_bit(0,(lock)))
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
 #define spin_lock_irq(lock) \
 	do { __cli(); spin_lock(lock); } while (0)
@@ -158,12 +134,12 @@
 	asm volatile("\n1:\t" \
 		     "lock ; incl %0\n\t" \
 		     "js 2f\n" \
-		     ".text 2\n" \
+		     ".section .text.lock,\"ax\"\n" \
 		     "2:\tlock ; decl %0\n" \
 		     "3:\tcmpl $0,%0\n\t" \
 		     "js 3b\n\t" \
 		     "jmp 1b\n" \
-		     ".text" \
+		     ".previous" \
 		     :"=m" (__dummy_lock(&(rw)->lock)))
 
 #define read_unlock(rw) \
@@ -173,19 +149,15 @@
 #define write_lock(rw) \
 	asm volatile("\n1:\t" \
 		     "lock ; btsl $31,%0\n\t" \
-		     "jc 3f\n\t" \
-		     "testl $0x7fffffff,%0\n\t" \
-		     "jne 4f\n" \
-		     "2:\n" \
-		     ".text 2\n" \
-		     "3:\ttestl $-1,%0\n\t" \
-		     "js 3b\n\t" \
-		     "lock ; btsl $31,%0\n\t" \
-		     "jc 3b\n" \
-		     "4:\ttestl $0x7fffffff,%0\n\t" \
+		     "jc 4f\n" \
+		     "2:\ttestl $0x7fffffff,%0\n\t" \
+		     "jne 3f\n" \
+		     ".section .text.lock,\"ax\"\n" \
+		     "3:\tlock ; btrl $31,%0\n" \
+		     "4:\tcmp $0,%0\n\t" \
 		     "jne 4b\n\t" \
-		     "jmp 2b\n" \
-		     ".text" \
+		     "jmp 1b\n" \
+		     ".previous" \
 		     :"=m" (__dummy_lock(&(rw)->lock)))
 
 #define write_unlock(rw) \
diff -u --recursive --new-file v2.1.36/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.36/linux/include/asm-i386/system.h	Mon Apr 14 16:28:19 1997
+++ linux/include/asm-i386/system.h	Mon May 12 10:35:43 1997
@@ -73,7 +73,6 @@
 		__asm__ __volatile__("fwait"); \
 		prev->flags&=~PF_USEDFPU;	 \
 	} \
-	current_set[this_cpu] = next; \
 __asm__("ljmp %0\n\t" \
 	: /* no output */ \
 	:"m" (*(((char *)&next->tss.tr)-4)), \
@@ -91,8 +90,7 @@
 
 #else
 #define switch_to(prev,next) do { \
-__asm__("movl %2,"SYMBOL_NAME_STR(current_set)"\n\t" \
-	"ljmp %0\n\t" \
+__asm__("ljmp %0\n\t" \
 	"cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
 	"jne 1f\n\t" \
 	"clts\n" \
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/dsp56k.h linux/include/asm-m68k/dsp56k.h
--- v2.1.36/linux/include/asm-m68k/dsp56k.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/dsp56k.h	Mon May 12 10:35:43 1997
@@ -33,38 +33,3 @@
 #define DSP56K_SET_RX_WSIZE	3    /* Host receive word size (1-4)    */
 #define DSP56K_HOST_FLAGS	4    /* Host flag registers             */
 #define DSP56K_HOST_CMD         5    /* Trig Host Command (0-31)        */
-/*
- * linux/include/asm-m68k/dsp56k.h - defines and declarations for
- *                                   DSP56k device driver
- *
- * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-/* Used for uploading DSP binary code */
-struct dsp56k_upload {
-	int len;
-	char *bin;
-};
-
-/* For the DSP host flags */
-struct dsp56k_host_flags {
-	int dir;     /* Bit field. 1 = write output bit, 0 = do nothing.
-		      * 0x0000 means reading only, 0x0011 means
-		      * writing the bits stored in `out' on HF0 and HF1.
-		      * Note that HF2 and HF3 can only be read.
-		      */
-	int out;     /* Bit field like above. */
-	int status;  /* Host register's current state is returned */
-};
-
-/* ioctl command codes */
-#define DSP56K_UPLOAD	        1    /* Upload DSP binary program       */
-#define DSP56K_SET_TX_WSIZE	2    /* Host transmit word size (1-4)   */
-#define DSP56K_SET_RX_WSIZE	3    /* Host receive word size (1-4)    */
-#define DSP56K_HOST_FLAGS	4    /* Host flag registers             */
-#define DSP56K_HOST_CMD         5    /* Trig Host Command (0-31)        */
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/fpu.h linux/include/asm-m68k/fpu.h
--- v2.1.36/linux/include/asm-m68k/fpu.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/fpu.h	Mon May 12 10:35:43 1997
@@ -18,23 +18,3 @@
 #endif
 
 #endif /* __M68K_FPU_H */
-#ifndef __M68K_FPU_H
-#define __M68K_FPU_H
-
-#include <linux/config.h>
-
-/*
- * MAX floating point unit state size (FSAVE/FRESTORE)
- */
-
-#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
-#define FPSTATESIZE (216/sizeof(unsigned char))
-#elif defined(CONFIG_M68040)
-#define FPSTATESIZE (96/sizeof(unsigned char))
-#elif defined(CONFIG_M68060)
-#define FPSTATESIZE (12/sizeof(unsigned char))
-#else
-#define FPSTATESIZE error no_cpu_type_configured
-#endif
-
-#endif /* __M68K_FPU_H */
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.1.36/linux/include/asm-m68k/hardirq.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/hardirq.h	Mon May 12 10:35:43 1997
@@ -11,16 +11,3 @@
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
 
 #endif
-#ifndef __M68K_HARDIRQ_H
-#define __M68K_HARDIRQ_H
-
-extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
-
-#define hardirq_trylock(cpu)	((cpu)==0)	/* always true */
-#define hardirq_endlock(cpu)	do { } while (0)
-
-#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h
--- v2.1.36/linux/include/asm-m68k/init.h	Wed Apr 16 14:15:00 1997
+++ linux/include/asm-m68k/init.h	Mon May 12 10:35:43 1997
@@ -1,14 +1,14 @@
 #ifndef _M68K_INIT_H
 #define _M68K_INIT_H
 
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define	__init
-#define __initdata
-#define __initfunc(__arginit) __arginit
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+	__arginit __init; \
+	__arginit
 /* For assembly routines */
-#define __INIT
-#define __FINIT
-#define __INITDATA
+#define __INIT		.section	".text.init",#alloc,#execinstr
+#define __FINIT		.previous
+#define __INITDATA	.section	".data.init",#alloc,#write
 
 #endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/namei.h linux/include/asm-m68k/namei.h
--- v2.1.36/linux/include/asm-m68k/namei.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/namei.h	Mon May 12 10:35:43 1997
@@ -19,24 +19,3 @@
 	do { } while (0)
 
 #endif
-/*
- * linux/include/asm-m68k/namei.h
- *
- * Included from linux/fs/namei.c
- */
-
-#ifndef __M68K_NAMEI_H
-#define __M68K_NAMEI_H
-
-/* These dummy routines maybe changed to something useful
- * for /usr/gnemul/ emulation stuff.
- * Look at asm-sparc/namei.h for details.
- */
-
-#define translate_namei(pathname, base, follow_links, res_inode)	\
-	do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
-	do { } while (0)
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/poll.h linux/include/asm-m68k/poll.h
--- v2.1.36/linux/include/asm-m68k/poll.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/poll.h	Mon May 12 10:35:43 1997
@@ -19,24 +19,3 @@
 };
 
 #endif
-#ifndef __m68k_POLL_H
-#define __m68k_POLL_H
-
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
-#define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
-#define POLLWRBAND	256
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.1.36/linux/include/asm-m68k/processor.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/processor.h	Mon May 12 10:35:43 1997
@@ -44,7 +44,7 @@
 	unsigned char  fpstate[FPSTATESIZE];  /* floating point state */
 };
 
-#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
 	sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.1.36/linux/include/asm-m68k/semaphore.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/semaphore.h	Mon May 12 10:35:43 1997
@@ -1,6 +1,7 @@
 #ifndef _M68K_SEMAPHORE_H
 #define _M68K_SEMAPHORE_H
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -38,6 +39,7 @@
 
 static inline int waking_non_zero(struct semaphore *sem)
 {
+#ifndef CONFIG_RMW_INSNS
 	unsigned long flags;
 	int ret = 0;
 
@@ -48,6 +50,21 @@
 		ret = 1;
 	}
 	restore_flags(flags);
+#else
+	int ret, tmp;
+
+	__asm__ __volatile__
+	  ("1:	movel	%2,%0\n"
+	   "	jeq	3f\n"
+	   "2:	movel	%0,%1\n"
+	   "	subql	#1,%1\n"
+	   "	casl	%0,%1,%2\n"
+	   "	jeq	3f\n"
+	   "	tstl	%0\n"
+	   "	jne	2b\n"
+	   "3:"
+	   : "=d" (ret), "=d" (tmp), "=m" (sem->waking));
+#endif
 	return ret;
 }
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/sigcontext.h linux/include/asm-m68k/sigcontext.h
--- v2.1.36/linux/include/asm-m68k/sigcontext.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/sigcontext.h	Mon May 12 10:35:43 1997
@@ -1,8 +1,6 @@
 #ifndef _ASM_M68k_SIGCONTEXT_H
 #define _ASM_M68k_SIGCONTEXT_H
 
-#include<asm/fpu.h>
-
 struct sigcontext {
 	unsigned long  sc_mask; 	/* old sigmask */
 	unsigned long  sc_usp;		/* old user stack pointer */
@@ -15,7 +13,7 @@
 	unsigned short sc_formatvec;
 	unsigned long  sc_fpregs[2*3];  /* room for two fp registers */
 	unsigned long  sc_fpcntl[3];
-	unsigned char  sc_fpstate[FPSTATESIZE];
+	unsigned char  sc_fpstate[216];
 };
 
 #endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/smp_lock.h linux/include/asm-m68k/smp_lock.h
--- v2.1.36/linux/include/asm-m68k/smp_lock.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/smp_lock.h	Mon May 12 10:35:43 1997
@@ -12,17 +12,3 @@
 #define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
 
 #endif
-#ifndef __M68K_SMPLOCK_H
-#define __M68K_SMPLOCK_H
-
-/*
- * We don't do SMP so this is again one of these silly dummy files
- * to keep the kernel source looking nice ;-(.
- */
-
-#define lock_kernel()		do { } while(0)
-#define unlock_kernel()		do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reaquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h
--- v2.1.36/linux/include/asm-m68k/softirq.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/softirq.h	Mon May 12 10:35:43 1997
@@ -60,59 +60,3 @@
 #define softirq_endlock()  (__m68k_bh_counter = 0)
 
 #endif
-#ifndef __M68K_SOFTIRQ_H
-#define __M68K_SOFTIRQ_H
-
-/*
- * Software interrupts.. no SMP here either.
- */
-#define get_active_bhs()	(bh_mask & bh_active)
-#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	bh_mask_count[nr] = 0;
-	bh_mask |= 1 << nr;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	bh_mask_count[nr]++;
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (!--bh_mask_count[nr])
-		bh_mask |= 1 << nr;
-}
-
-extern int __m68k_bh_counter;
-
-extern inline void start_bh_atomic(void)
-{
-	__m68k_bh_counter++;
-	barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
-	barrier();
-	__m68k_bh_counter--;
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock()  (__m68k_bh_counter ? 0 : (__m68k_bh_counter=1))
-#define softirq_endlock()  (__m68k_bh_counter = 0)
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-m68k/spinlock.h linux/include/asm-m68k/spinlock.h
--- v2.1.36/linux/include/asm-m68k/spinlock.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/spinlock.h	Mon May 12 10:35:43 1997
@@ -49,26 +49,3 @@
 #define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
 
 #endif
-#ifndef __M68K_SPINLOCK_H
-#define __M68K_SPINLOCK_H
-
-/*
- * We don't do SMP on the m68k .... at least not yet.
- */
-
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-
-#define spin_lock_irqsave(lock, flags) \
-	do { save_flags(flags); cli(); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
-	restore_flags(flags)
-
-#endif
diff -u --recursive --new-file v2.1.36/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.1.36/linux/include/asm-mips/processor.h	Mon Apr 14 16:28:19 1997
+++ linux/include/asm-mips/processor.h	Mon May 12 10:35:43 1997
@@ -139,7 +139,7 @@
 #if !defined (__LANGUAGE_ASSEMBLY__)
 
 #define INIT_MMAP { &init_mm, KSEG0, KSEG1, PAGE_SHARED, \
-                    VM_READ | VM_WRITE | VM_EXEC }
+                    VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
         /* \
diff -u --recursive --new-file v2.1.36/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h
--- v2.1.36/linux/include/asm-mips/unistd.h	Fri Apr  4 08:52:25 1997
+++ linux/include/asm-mips/unistd.h	Mon May 12 10:35:43 1997
@@ -1149,7 +1149,7 @@
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls		157
+#define __NR_Linux_syscalls		158
 
 #ifndef __LANGUAGE_ASSEMBLY__
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.1.36/linux/include/asm-ppc/processor.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-ppc/processor.h	Mon May 12 10:35:43 1997
@@ -116,7 +116,7 @@
 }
 
 #define INIT_MMAP { &init_mm, 0, 0x40000000, \
-		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.1.36/linux/include/asm-sparc/asm_offsets.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-sparc/asm_offsets.h	Mon May 12 10:35:43 1997
@@ -30,123 +30,125 @@
 #define ASIZ_task_next_run	0x00000004
 #define AOFF_task_prev_run	0x00000050
 #define ASIZ_task_prev_run	0x00000004
-#define AOFF_task_saved_kernel_stack	0x00000054
-#define ASIZ_task_saved_kernel_stack	0x00000004
-#define AOFF_task_kernel_stack_page	0x00000058
-#define ASIZ_task_kernel_stack_page	0x00000004
-#define AOFF_task_exit_code	0x0000005c
+#define AOFF_task_exit_code	0x00000054
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x00000060
+#define AOFF_task_exit_signal	0x00000058
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_personality	0x00000064
+#define AOFF_task_personality	0x0000005c
 #define ASIZ_task_personality	0x00000004
-#define AOFF_task_pid	0x0000006c
+#define AOFF_task_pid	0x00000064
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x00000070
+#define AOFF_task_pgrp	0x00000068
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x00000074
+#define AOFF_task_tty_old_pgrp	0x0000006c
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x00000078
+#define AOFF_task_session	0x00000070
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x0000007c
+#define AOFF_task_leader	0x00000074
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_ngroups	0x00000080
+#define AOFF_task_ngroups	0x00000078
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000084
+#define AOFF_task_groups	0x0000007c
 #define ASIZ_task_groups	0x00000040
-#define AOFF_task_p_opptr	0x000000c4
+#define AOFF_task_p_opptr	0x000000bc
 #define ASIZ_task_p_opptr	0x00000004
-#define AOFF_task_p_pptr	0x000000c8
+#define AOFF_task_p_pptr	0x000000c0
 #define ASIZ_task_p_pptr	0x00000004
-#define AOFF_task_p_cptr	0x000000cc
+#define AOFF_task_p_cptr	0x000000c4
 #define ASIZ_task_p_cptr	0x00000004
-#define AOFF_task_p_ysptr	0x000000d0
+#define AOFF_task_p_ysptr	0x000000c8
 #define ASIZ_task_p_ysptr	0x00000004
-#define AOFF_task_p_osptr	0x000000d4
+#define AOFF_task_p_osptr	0x000000cc
 #define ASIZ_task_p_osptr	0x00000004
-#define AOFF_task_wait_chldexit	0x000000d8
+#define AOFF_task_pidhash_next	0x000000d0
+#define ASIZ_task_pidhash_next	0x00000004
+#define AOFF_task_pidhash_pprev	0x000000d4
+#define ASIZ_task_pidhash_pprev	0x00000004
+#define AOFF_task_tarray_ptr	0x000000d8
+#define ASIZ_task_tarray_ptr	0x00000004
+#define AOFF_task_wait_chldexit	0x000000dc
 #define ASIZ_task_wait_chldexit	0x00000004
-#define AOFF_task_uid	0x000000dc
+#define AOFF_task_uid	0x000000e0
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x000000de
+#define AOFF_task_euid	0x000000e2
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x000000e0
+#define AOFF_task_suid	0x000000e4
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x000000e2
+#define AOFF_task_fsuid	0x000000e6
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x000000e4
+#define AOFF_task_gid	0x000000e8
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x000000e6
+#define AOFF_task_egid	0x000000ea
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x000000e8
+#define AOFF_task_sgid	0x000000ec
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x000000ea
+#define AOFF_task_fsgid	0x000000ee
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_timeout	0x000000ec
+#define AOFF_task_timeout	0x000000f0
 #define ASIZ_task_timeout	0x00000004
-#define AOFF_task_policy	0x000000f0
+#define AOFF_task_policy	0x000000f4
 #define ASIZ_task_policy	0x00000004
-#define AOFF_task_rt_priority	0x000000f4
+#define AOFF_task_rt_priority	0x000000f8
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x000000f8
+#define AOFF_task_it_real_value	0x000000fc
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000fc
+#define AOFF_task_it_prof_value	0x00000100
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x00000100
+#define AOFF_task_it_virt_value	0x00000104
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x00000104
+#define AOFF_task_it_real_incr	0x00000108
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x00000108
+#define AOFF_task_it_prof_incr	0x0000010c
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x0000010c
+#define AOFF_task_it_virt_incr	0x00000110
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x00000110
+#define AOFF_task_real_timer	0x00000114
 #define ASIZ_task_real_timer	0x00000014
-#define AOFF_task_utime	0x00000124
+#define AOFF_task_utime	0x00000128
 #define ASIZ_task_utime	0x00000004
-#define AOFF_task_stime	0x00000128
+#define AOFF_task_stime	0x0000012c
 #define ASIZ_task_stime	0x00000004
-#define AOFF_task_cutime	0x0000012c
+#define AOFF_task_cutime	0x00000130
 #define ASIZ_task_cutime	0x00000004
-#define AOFF_task_cstime	0x00000130
+#define AOFF_task_cstime	0x00000134
 #define ASIZ_task_cstime	0x00000004
-#define AOFF_task_start_time	0x00000134
+#define AOFF_task_start_time	0x00000138
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_min_flt	0x00000138
+#define AOFF_task_min_flt	0x0000013c
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x0000013c
+#define AOFF_task_maj_flt	0x00000140
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x00000140
+#define AOFF_task_nswap	0x00000144
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x00000144
+#define AOFF_task_cmin_flt	0x00000148
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x00000148
+#define AOFF_task_cmaj_flt	0x0000014c
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x0000014c
+#define AOFF_task_cnswap	0x00000150
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_swap_address	0x00000154
+#define AOFF_task_swap_address	0x00000158
 #define ASIZ_task_swap_address	0x00000004
-#define AOFF_task_old_maj_flt	0x00000158
+#define AOFF_task_old_maj_flt	0x0000015c
 #define ASIZ_task_old_maj_flt	0x00000004
-#define AOFF_task_dec_flt	0x0000015c
+#define AOFF_task_dec_flt	0x00000160
 #define ASIZ_task_dec_flt	0x00000004
-#define AOFF_task_swap_cnt	0x00000160
+#define AOFF_task_swap_cnt	0x00000164
 #define ASIZ_task_swap_cnt	0x00000004
-#define AOFF_task_rlim	0x00000164
+#define AOFF_task_rlim	0x00000168
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000001b4
+#define AOFF_task_used_math	0x000001b8
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000001b6
+#define AOFF_task_comm	0x000001ba
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000001c8
+#define AOFF_task_link_count	0x000001cc
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000001cc
+#define AOFF_task_tty	0x000001d0
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000001d0
+#define AOFF_task_semundo	0x000001d4
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000001d4
+#define AOFF_task_semsleeping	0x000001d8
 #define ASIZ_task_semsleeping	0x00000004
-#define AOFF_task_ldt	0x000001d8
+#define AOFF_task_ldt	0x000001dc
 #define ASIZ_task_ldt	0x00000004
 #define AOFF_task_tss	0x000001e0
 #define ASIZ_task_tss	0x00000390
@@ -158,56 +160,60 @@
 #define ASIZ_task_mm	0x00000004
 #define AOFF_task_sig	0x0000057c
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_processor	0x00000580
+#define AOFF_task_has_cpu	0x00000580
+#define ASIZ_task_has_cpu	0x00000004
+#define AOFF_task_processor	0x00000584
 #define ASIZ_task_processor	0x00000004
-#define AOFF_task_last_processor	0x00000584
+#define AOFF_task_last_processor	0x00000588
 #define ASIZ_task_last_processor	0x00000004
-#define AOFF_task_lock_depth	0x00000588
+#define AOFF_task_lock_depth	0x0000058c
 #define ASIZ_task_lock_depth	0x00000004
-#define AOFF_mm_count	0x00000000
-#define ASIZ_mm_count	0x00000004
-#define AOFF_mm_pgd	0x00000004
+#define AOFF_task_sigmask_lock	0x00000590
+#define ASIZ_task_sigmask_lock	0x00000000
+#define AOFF_mm_mmap	0x00000000
+#define ASIZ_mm_mmap	0x00000004
+#define AOFF_mm_mmap_cache	0x00000004
+#define ASIZ_mm_mmap_cache	0x00000004
+#define AOFF_mm_pgd	0x00000008
 #define ASIZ_mm_pgd	0x00000004
-#define AOFF_mm_context	0x00000008
+#define AOFF_mm_count	0x0000000c
+#define ASIZ_mm_count	0x00000004
+#define AOFF_mm_mmap_sem	0x00000010
+#define ASIZ_mm_mmap_sem	0x0000000c
+#define AOFF_mm_context	0x0000001c
 #define ASIZ_mm_context	0x00000004
-#define AOFF_mm_start_code	0x0000000c
+#define AOFF_mm_start_code	0x00000020
 #define ASIZ_mm_start_code	0x00000004
-#define AOFF_mm_end_code	0x00000010
+#define AOFF_mm_end_code	0x00000024
 #define ASIZ_mm_end_code	0x00000004
-#define AOFF_mm_start_data	0x00000014
+#define AOFF_mm_start_data	0x00000028
 #define ASIZ_mm_start_data	0x00000004
-#define AOFF_mm_end_data	0x00000018
+#define AOFF_mm_end_data	0x0000002c
 #define ASIZ_mm_end_data	0x00000004
-#define AOFF_mm_start_brk	0x0000001c
+#define AOFF_mm_start_brk	0x00000030
 #define ASIZ_mm_start_brk	0x00000004
-#define AOFF_mm_brk	0x00000020
+#define AOFF_mm_brk	0x00000034
 #define ASIZ_mm_brk	0x00000004
-#define AOFF_mm_start_stack	0x00000024
+#define AOFF_mm_start_stack	0x00000038
 #define ASIZ_mm_start_stack	0x00000004
-#define AOFF_mm_start_mmap	0x00000028
+#define AOFF_mm_start_mmap	0x0000003c
 #define ASIZ_mm_start_mmap	0x00000004
-#define AOFF_mm_arg_start	0x0000002c
+#define AOFF_mm_arg_start	0x00000040
 #define ASIZ_mm_arg_start	0x00000004
-#define AOFF_mm_arg_end	0x00000030
+#define AOFF_mm_arg_end	0x00000044
 #define ASIZ_mm_arg_end	0x00000004
-#define AOFF_mm_env_start	0x00000034
+#define AOFF_mm_env_start	0x00000048
 #define ASIZ_mm_env_start	0x00000004
-#define AOFF_mm_env_end	0x00000038
+#define AOFF_mm_env_end	0x0000004c
 #define ASIZ_mm_env_end	0x00000004
-#define AOFF_mm_rss	0x0000003c
+#define AOFF_mm_rss	0x00000050
 #define ASIZ_mm_rss	0x00000004
-#define AOFF_mm_total_vm	0x00000040
+#define AOFF_mm_total_vm	0x00000054
 #define ASIZ_mm_total_vm	0x00000004
-#define AOFF_mm_locked_vm	0x00000044
+#define AOFF_mm_locked_vm	0x00000058
 #define ASIZ_mm_locked_vm	0x00000004
-#define AOFF_mm_def_flags	0x00000048
+#define AOFF_mm_def_flags	0x0000005c
 #define ASIZ_mm_def_flags	0x00000004
-#define AOFF_mm_mmap	0x0000004c
-#define ASIZ_mm_mmap	0x00000004
-#define AOFF_mm_mmap_avl	0x00000050
-#define ASIZ_mm_mmap_avl	0x00000004
-#define AOFF_mm_mmap_sem	0x00000054
-#define ASIZ_mm_mmap_sem	0x0000000c
 #define AOFF_thread_uwinmask	0x00000000
 #define ASIZ_thread_uwinmask	0x00000004
 #define AOFF_thread_kregs	0x00000004
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/asmmacro.h linux/include/asm-sparc/asmmacro.h
--- v2.1.36/linux/include/asm-sparc/asmmacro.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/asmmacro.h	Mon May 12 10:35:43 1997
@@ -6,22 +6,22 @@
 #ifndef _SPARC_ASMMACRO_H
 #define _SPARC_ASMMACRO_H
 
-/* #define SMP_DEBUG */
-
 #define GET_PROCESSOR_ID(reg) \
 	rd	%tbr, %reg; \
 	srl	%reg, 12, %reg; \
 	and	%reg, 3, %reg;
 
 #define GET_PROCESSOR_MID(reg, tmp) \
-	GET_PROCESSOR_ID(reg) \
-	set	C_LABEL(mid_xlate), %tmp; \
+	rd	%tbr, %reg; \
+	sethi	C_LABEL(mid_xlate), %tmp; \
+	srl	%reg, 12, %reg; \
+	or	%tmp, %lo(C_LABEL(mid_xlate)), %tmp; \
+	and	%reg, 3, %reg; \
 	ldub	[%tmp + %reg], %reg;
 
 #define GET_PROCESSOR_OFFSET(reg) \
-	rd	%tbr, %reg; \
-	srl	%reg, 10, %reg; \
-	and	%reg, 0xc, %reg;
+	GET_PROCESSOR_ID(reg) \
+	sll	%reg, 2, %reg;
 
 #define PROCESSOR_OFFSET_TO_ID(reg) \
 	srl	%reg, 2, %reg;
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h
--- v2.1.36/linux/include/asm-sparc/auxio.h	Mon Mar 17 14:54:31 1997
+++ linux/include/asm-sparc/auxio.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.16 1997/01/31 23:26:05 tdyas Exp $
+/* $Id: auxio.h,v 1.17 1997/05/01 01:42:02 davem Exp $
  * auxio.h:  Definitions and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -43,30 +43,27 @@
 #define FLPY_TCNTOFF  if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_TCNT))
 
 #ifndef __ASSEMBLY__
-extern __inline__ void set_auxio(unsigned char bits_on, unsigned char bits_off)
-{
-	unsigned char regval;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	switch(sparc_cpu_model) {
-	case sun4c:
-		regval = *AUXREG;
-		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN;
-		break;
-	case sun4m:
-		if(!AUXREG)
-			break;     /* VME chassic sun4m, no auxio. */
-		regval = *AUXREG;
-		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
-		break;
-	default:
-		panic("Can't set AUXIO register on this machine.");
-	};
-
-	restore_flags(flags);
-}
+#define set_auxio(bits_on, bits_off) \
+do { \
+	unsigned char regval; \
+	unsigned long flags; \
+	save_flags(flags); cli(); \
+	switch(sparc_cpu_model) { \
+	case sun4c: \
+		regval = *AUXREG; \
+		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN; \
+		break; \
+	case sun4m: \
+		if(!AUXREG) \
+			break;     /* VME chassic sun4m, no auxio. */ \
+		regval = *AUXREG; \
+		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M; \
+		break; \
+	default: \
+		panic("Can't set AUXIO register on this machine."); \
+	}; \
+	restore_flags(flags); \
+} while(0)
 #endif /* !(__ASSEMBLY__) */
 
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/linux_logo.h linux/include/asm-sparc/linux_logo.h
--- v2.1.36/linux/include/asm-sparc/linux_logo.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/linux_logo.h	Mon May 12 10:35:43 1997
@@ -1043,1048 +1043,3 @@
 "'!!!!!!!W..e$$!!!!!!`    %s\n"
 " \"~^^~         ^~~^\n"
 "\n";
-/* $Id: linux_logo.h,v 1.1 1997/04/16 17:51:24 jj Exp $
- * include/asm-sparc/linux_logo.h: This is a linux logo
- *                                 to be displayed on boot.
- *
- * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
- * image size has to be 80x80
- * values have to start from 0x20
- * (i.e. RGB(linux_logo_red[0],
- *	     linux_logo_green[0],
- *	     linux_logo_blue[0]) is color 0x20)
- * BW image has to be 80x80 as well, with MS bit
- * on the left
- * Serial_console ascii image can be any size,
- * but should contain %s to display the version
- */
- 
-#include <linux/init.h>
-#include <linux/version.h>
-
-#define linux_logo_banner "Linux/SPARC version " UTS_RELEASE
-
-#define LINUX_LOGO_COLORS 221
-
-unsigned char linux_logo_red[] __initdata = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
-  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
-  0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
-  0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
-  0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
-  0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
-  0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
-  0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
-  0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
-  0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
-  0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
-  0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
-  0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
-  0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
-  0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
-  0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
-  0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
-  0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_green[] __initdata = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
-  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
-  0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
-  0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
-  0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
-  0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
-  0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
-  0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
-  0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
-  0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
-  0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
-  0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
-  0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
-  0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
-  0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
-  0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
-  0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
-  0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo_blue[] __initdata = {
-  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
-  0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
-  0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
-  0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
-  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
-  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
-  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
-  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
-  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
-  0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
-  0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
-  0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
-  0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
-  0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
-  0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
-  0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
-  0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
-  0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
-  0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
-  0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
-  0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
-  0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
-  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
-  0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
-  0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
-  0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
-  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
-  0x1D, 0x14, 0x06, 0x02, 0x00
-};
-
-unsigned char linux_logo[] __initdata = {
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
-  0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
-  0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
-  0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
-  0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
-  0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
-  0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
-  0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
-  0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
-  0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
-  0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
-  0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
-  0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
-  0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
-  0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
-  0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
-  0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
-  0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
-  0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
-  0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
-  0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
-  0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
-  0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
-  0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
-  0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
-  0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
-  0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
-  0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
-  0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
-  0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
-  0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
-  0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
-  0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
-  0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
-  0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
-  0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
-  0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
-  0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
-  0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
-  0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
-  0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
-  0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
-  0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
-  0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
-  0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
-  0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
-  0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
-  0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
-  0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
-  0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
-  0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
-  0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
-  0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
-  0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
-  0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
-  0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
-  0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
-  0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
-  0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
-  0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
-  0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
-  0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
-  0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
-  0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
-  0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
-  0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
-  0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
-  0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
-  0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
-  0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
-  0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
-  0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
-  0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
-  0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
-  0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
-  0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
-  0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
-  0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
-  0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
-  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
-  0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
-  0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
-  0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
-  0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
-  0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
-  0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
-  0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
-  0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
-  0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
-  0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
-  0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
-  0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
-  0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
-  0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
-  0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
-  0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
-  0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
-  0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
-  0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
-  0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
-  0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
-  0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
-  0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
-  0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
-  0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
-  0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
-  0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
-  0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
-  0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
-  0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
-  0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
-  0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
-  0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
-  0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
-  0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
-  0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
-  0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
-  0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
-  0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
-  0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
-  0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
-  0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
-  0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
-  0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
-  0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
-  0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
-  0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
-  0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
-  0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
-  0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
-  0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
-  0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
-  0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
-  0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
-  0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
-  0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
-  0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
-  0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
-  0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
-  0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
-  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
-  0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
-  0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
-  0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
-  0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
-  0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
-  0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
-  0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
-  0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
-  0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
-  0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
-  0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
-  0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
-  0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
-  0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
-  0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
-  0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
-  0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
-  0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
-  0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
-  0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
-  0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
-  0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
-  0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
-  0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
-  0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
-  0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
-  0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
-  0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
-  0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
-  0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
-  0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
-  0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
-  0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
-  0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
-  0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
-  0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
-  0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
-  0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
-  0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
-  0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
-  0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
-  0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
-  0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
-  0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
-  0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
-  0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
-  0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
-  0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
-  0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
-  0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
-  0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
-  0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
-  0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
-  0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
-  0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
-  0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
-  0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
-  0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
-  0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
-  0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
-  0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
-  0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
-  0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
-  0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
-  0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
-  0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
-  0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
-  0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
-  0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
-  0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
-  0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
-  0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
-  0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
-  0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
-  0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
-  0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
-  0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
-  0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
-  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
-  0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
-  0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
-  0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
-  0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
-  0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
-  0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
-  0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
-  0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
-  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
-  0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
-  0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
-  0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
-  0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
-  0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
-  0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
-  0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
-  0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
-  0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
-  0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
-  0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
-  0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
-  0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
-  0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
-  0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
-  0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
-  0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
-  0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
-  0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
-  0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
-  0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
-  0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
-  0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
-  0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
-  0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
-  0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
-  0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
-  0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
-  0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
-  0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
-  0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
-  0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
-  0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
-  0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
-  0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
-  0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
-  0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
-  0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
-  0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
-  0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
-  0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
-  0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
-  0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
-  0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
-  0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
-  0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
-  0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
-  0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
-  0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
-  0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
-  0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
-  0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
-  0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
-  0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
-  0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
-  0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
-  0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
-  0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
-  0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
-  0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
-  0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
-  0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
-  0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
-  0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
-  0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
-  0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
-  0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
-  0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
-  0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
-  0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
-  0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
-  0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
-  0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
-  0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
-  0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
-  0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
-  0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
-  0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
-  0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
-  0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
-  0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
-  0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
-  0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
-  0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
-  0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
-  0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
-  0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
-  0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
-  0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
-  0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
-  0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
-  0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
-  0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
-  0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
-  0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
-  0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
-  0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
-  0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
-  0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
-  0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
-  0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
-  0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
-  0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
-  0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
-  0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
-  0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
-  0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
-  0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
-  0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
-  0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
-  0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
-  0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
-  0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
-  0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
-  0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
-  0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
-  0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
-  0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
-  0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
-  0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
-  0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
-  0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
-  0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
-  0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
-  0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
-  0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
-  0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
-  0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
-  0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
-  0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
-  0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
-  0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
-  0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
-  0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
-  0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
-  0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
-  0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
-  0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
-  0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
-  0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
-  0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
-  0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
-  0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
-  0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
-  0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
-  0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
-  0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
-  0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
-  0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
-  0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
-  0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
-  0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
-  0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
-  0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
-  0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
-  0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
-  0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
-  0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
-  0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
-  0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
-  0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
-  0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
-  0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
-  0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
-  0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
-  0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
-  0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
-  0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
-  0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
-  0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
-  0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
-  0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
-  0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
-  0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
-  0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
-  0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
-  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
-  0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
-  0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
-  0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
-  0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
-  0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
-  0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
-  0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
-  0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
-  0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
-  0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
-  0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
-  0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
-  0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
-  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
-  0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
-  0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
-  0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
-  0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
-  0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
-  0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
-  0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
-  0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
-  0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
-  0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
-  0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
-  0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
-  0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
-  0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
-  0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
-  0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
-  0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
-  0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
-  0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
-  0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
-  0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
-  0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
-  0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
-  0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
-  0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
-  0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
-  0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
-  0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
-  0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
-  0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
-  0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
-  0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
-  0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
-  0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
-  0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
-  0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
-  0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
-  0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
-  0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
-  0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
-  0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
-  0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
-  0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
-  0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
-  0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
-  0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
-  0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
-  0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
-  0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
-  0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
-  0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
-  0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
-  0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
-  0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
-  0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
-  0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
-  0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
-  0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
-  0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
-  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
-  0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
-  0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
-  0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
-  0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
-  0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
-  0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
-  0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
-  0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
-  0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
-  0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
-  0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
-  0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
-  0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
-  0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
-  0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
-  0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
-  0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
-  0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
-  0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
-  0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
-  0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
-  0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
-  0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
-  0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
-  0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
-  0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
-  0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
-  0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
-  0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
-  0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
-  0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
-  0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
-  0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
-  0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
-  0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
-  0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
-  0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
-  0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
-  0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
-  0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
-  0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
-  0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
-  0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
-  0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
-  0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
-  0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
-  0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
-  0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
-  0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
-  0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
-  0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
-  0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
-  0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
-  0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
-  0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
-  0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
-  0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
-  0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
-  0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
-  0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
-  0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
-  0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
-  0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
-  0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
-  0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
-  0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
-  0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
-  0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
-  0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
-  0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
-  0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
-  0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
-  0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
-  0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
-  0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
-  0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
-  0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
-  0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
-  0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
-  0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
-  0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
-  0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
-  0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
-  0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
-  0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
-  0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
-  0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
-  0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
-  0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
-  0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
-  0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
-  0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
-  0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
-  0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
-  0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
-  0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
-  0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
-  0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
-  0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
-  0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
-  0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
-  0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
-  0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
-  0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
-  0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
-  0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
-  0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
-  0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
-  0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
-  0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
-  0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
-  0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
-  0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
-  0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
-  0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
-  0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
-  0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
-  0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
-  0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
-  0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
-  0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
-  0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
-  0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
-  0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
-  0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
-  0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
-  0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
-  0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
-  0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
-  0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
-  0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
-  0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
-  0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
-  0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
-  0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
-  0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
-  0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
-  0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
-  0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
-  0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
-  0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
-  0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
-  0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
-  0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
-  0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
-  0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
-  0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
-  0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
-  0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
-  0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
-  0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
-  0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
-  0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
-  0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
-  0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
-  0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
-  0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
-  0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
-  0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
-  0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
-  0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
-  0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
-  0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
-  0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
-  0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
-  0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
-};
-
-unsigned char linux_logo_bw[] __initdata = {
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
-  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
-  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
-  0x99, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xF3, 0xBC, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
-  0x19, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
-  0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x21, 0xD8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0xC0, 0x1F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
-  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
-  0xC0, 0x7C, 0x04, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xE3, 0x80, 0x00, 0x7C, 0x40, 0x11, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0xD2, 0x29,
-  0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
-  0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
-  0x00, 0x3F, 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x1E, 0x00, 0x00, 0x1F, 0x80, 0x19, 0xFF, 0xFF,
-  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1E, 0x80, 0x19,
-  0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1E,
-  0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
-  0x00, 0x0F, 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC,
-  0xF8, 0x00, 0x00, 0x0E, 0x80, 0x11, 0xFF, 0xFF,
-  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x06, 0x00, 0x11,
-  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x06,
-  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
-  0x00, 0x02, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xF1,
-  0xF0, 0x00, 0x00, 0x02, 0x80, 0x10, 0xFF, 0xFF,
-  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x97, 0x10,
-  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
-  0xDF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
-  0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC7,
-  0xC0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8,
-  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
-  0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x9F,
-  0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
-  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0x18,
-  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
-  0xA8, 0x11, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
-  0x00, 0x02, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x99,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xFF, 0xFF,
-  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x01,
-  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
-  0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x40,
-  0x38, 0x00, 0x00, 0x00, 0xFE, 0x47, 0xFF, 0xFF,
-  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x23,
-  0xFF, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
-  0x78, 0x11, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
-  0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
-  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
-  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
-  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
-  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
-  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
-  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
-  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
-  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
-  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
-  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
-  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
-  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
-  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
-  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
-  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
-  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
-  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
-  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
-
-/* Painted by Johnny Stenback <jst@uwasa.fi> */
-
-unsigned char *linux_serial_image __initdata = "\n"
-"         .u$e.\n"
-"       .$$$$$:S\n"
-"       $\"*$/\"*$$\n"
-"       $.`$ . ^F\n"
-"       4k+#+T.$F\n"
-"       4P+++\"$\"$\n"
-"       :R\"+  t$$B\n"
-"    ___#       $$$\n"
-"    |  |       R$$k\n"
-"   dd. | Linux  $!$\n"
-"   ddd |  Sparc $9$F\n"
-" '!!!!!$       !!#!`\n"
-"  !!!!!*     .!!!!!`\n"
-"'!!!!!!!W..e$$!!!!!!`    %s\n"
-" \"~^^~         ^~~^\n"
-"\n";
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v2.1.36/linux/include/asm-sparc/processor.h	Mon Mar 17 14:54:31 1997
+++ linux/include/asm-sparc/processor.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.57 1997/03/04 16:27:22 jj Exp $
+/* $Id: processor.h,v 1.59 1997/05/01 01:42:03 davem Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@
 #define SPARC_FLAG_UNALIGNED    0x2    /* is allowed to do unaligned accesses */
 
 #define INIT_MMAP { &init_mm, (0), (0), \
-		    __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC }
+		    __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
 /* uwinmask, kregs, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
@@ -144,11 +144,14 @@
 #define release_thread(tsk)		do { } while(0)
 
 #ifdef __KERNEL__
+
 /* Allocation and freeing of basic task resources. */
-extern unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
-extern void (*free_kernel_stack)(unsigned long stack);
 extern struct task_struct *(*alloc_task_struct)(void);
 extern void (*free_task_struct)(struct task_struct *tsk);
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
+
 #endif
 
 #endif /* __ASM_SPARC_PROCESSOR_H */
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h
--- v2.1.36/linux/include/asm-sparc/semaphore.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/semaphore.h	Mon May 12 10:35:43 1997
@@ -28,20 +28,18 @@
  * XXX spinlock can allow this to be done without grabbing the IRQ
  * XXX global lock.
  */
-static inline int waking_non_zero(struct semaphore *sem)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	save_flags(flags);
-	cli();
-	if (atomic_read(&sem->waking) > 0) {
-		atomic_dec(&sem->waking);
-		ret = 1;
-	}
-	restore_flags(flags);
-	return ret;
-}
+#define waking_non_zero(sem) \
+({	unsigned long flags; \
+	int ret = 0; \
+	save_flags(flags); \
+	cli(); \
+	if (atomic_read(&sem->waking) > 0) { \
+		atomic_dec(&sem->waking); \
+		ret = 1; \
+	} \
+	restore_flags(flags); \
+	ret; \
+})
 
 /* This isn't quite as clever as the x86 side, I'll be fixing this
  * soon enough.
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.1.36/linux/include/asm-sparc/smp.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/smp.h	Mon May 12 10:35:43 1997
@@ -85,7 +85,7 @@
 extern __volatile__ int cpu_logical_map[NR_CPUS];
 extern unsigned long smp_proc_in_lock[NR_CPUS];
 
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
 {
 	int cpuid;
 
@@ -95,6 +95,8 @@
 			     "=&r" (cpuid));
 	return cpuid;
 }
+
+#define smp_processor_id() hard_smp_processor_id()
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.1.36/linux/include/asm-sparc/spinlock.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/spinlock.h	Mon May 12 10:35:43 1997
@@ -151,7 +151,7 @@
 	"b,a	1b\n\t"				\
 	".previous\n"				\
 	: "=r" (flags)				\
-	: "i" (PSR_PIL), "r" (lock)		\
+	: "i" (PSR_PIL), "r" (lp)		\
 	: "g2", "memory", "cc");		\
 } while(0)
 
@@ -198,7 +198,7 @@
  *
  * Unfortunately this scheme limits us to ~65,000 cpus.
  */
-extern __inline__ void read_lock(rwlock_t *rw)
+extern __inline__ void _read_lock(rwlock_t *rw)
 {
 	register rwlock_t *lp asm("g1");
 	lp = rw;
@@ -211,7 +211,14 @@
 	: "g2", "g4", "g7", "memory", "cc");
 }
 
-extern __inline__ void read_unlock(rwlock_t *rw)
+#define read_lock(lock) \
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_read_lock(lock); \
+	__restore_flags(flags); \
+} while(0)
+
+extern __inline__ void _read_unlock(rwlock_t *rw)
 {
 	register rwlock_t *lp asm("g1");
 	lp = rw;
@@ -224,6 +231,13 @@
 	: "g2", "g4", "g7", "memory", "cc");
 }
 
+#define read_unlock(lock) \
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_read_unlock(lock); \
+	__restore_flags(flags); \
+} while(0)
+
 extern __inline__ void write_lock(rwlock_t *rw)
 {
 	register rwlock_t *lp asm("g1");
@@ -238,15 +252,15 @@
 }
 
 #define write_unlock(rw)	do { (rw)->lock = 0; } while(0)
-#define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
-#define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
+#define read_lock_irq(lock)	do { __cli(); _read_lock(lock); } while (0)
+#define read_unlock_irq(lock)	do { _read_unlock(lock); __sti(); } while (0)
 #define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
 #define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
 
 #define read_lock_irqsave(lock, flags)	\
-	do { __save_and_cli(flags); read_lock(lock); } while (0)
+	do { __save_and_cli(flags); _read_lock(lock); } while (0)
 #define read_unlock_irqrestore(lock, flags) \
-	do { read_unlock(lock); __restore_flags(flags); } while (0)
+	do { _read_unlock(lock); __restore_flags(flags); } while (0)
 #define write_lock_irqsave(lock, flags)	\
 	do { __save_and_cli(flags); write_lock(lock); } while (0)
 #define write_unlock_irqrestore(lock, flags) \
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.1.36/linux/include/asm-sparc/system.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/system.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.58 1997/04/18 05:44:54 davem Exp $ */
+/* $Id: system.h,v 1.60 1997/05/01 02:26:56 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -108,7 +108,7 @@
 	"nop\n\t"									\
 	"nop\n\t"									\
 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" nop\n\t" : : "r" (&(current_set[smp_processor_id()])), "r" (next),		\
+	" nop\n\t" : : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),	\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
 	  "r" (task_pc)									\
@@ -233,12 +233,8 @@
 extern unsigned char global_irq_holder;
 
 #define save_flags(x) \
-do {	int cpuid; \
-	__asm__ __volatile__("rd %%tbr, %0; srl %0, 12, %0; and %0, 3, %0" \
-			     : "=r" (cpuid)); \
-	((x) = ((global_irq_holder == (unsigned char) cpuid) ? 1 : \
-		((getipl() & PSR_PIL) ? 2 : 0))); \
-} while(0)
+do {	((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+		((getipl() & PSR_PIL) ? 2 : 0))); } while(0)
 
 #define restore_flags(flags)						\
 do {	register unsigned long bits asm("g7");				\
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/termbits.h linux/include/asm-sparc/termbits.h
--- v2.1.36/linux/include/asm-sparc/termbits.h	Mon Apr 14 16:28:21 1997
+++ linux/include/asm-sparc/termbits.h	Mon May 12 10:35:43 1997
@@ -146,7 +146,13 @@
 #define HUPCL	  0x00000400
 #define CLOCAL	  0x00000800
 #define CBAUDEX   0x00001000
-#define  B76800   0x00001001
+/* We'll never see these speeds with the Zilogs, but for completeness... */
+#define  B57600   0x00001001
+#define  B115200  0x00001002
+#define  B230400  0x00001003
+#define  B460800  0x00001004
+/* This is what we can do with the Zilogs. */
+#define  B76800   0x00001005
 #define CIBAUD	  0x100f0000  /* input baud rate (not used) */
 #define CMSPAR	  0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS	  0x80000000  /* flow control */
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h
--- v2.1.36/linux/include/asm-sparc/winmacro.h	Mon Mar 17 14:54:33 1997
+++ linux/include/asm-sparc/winmacro.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: winmacro.h,v 1.18 1997/03/04 16:27:27 jj Exp $
+/* $Id: winmacro.h,v 1.19 1997/05/01 01:42:05 davem Exp $
  * winmacro.h: Window loading-unloading macros.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -114,12 +114,11 @@
 #ifdef __SMP__
 #define LOAD_CURRENT(dest_reg, idreg) \
         rd       %tbr, %idreg; \
-        srl      %idreg, 10, %idreg; \
-	and      %idreg, 0xc, %idreg; \
 	sethi    %hi(C_LABEL(current_set)), %dest_reg; \
+        srl      %idreg, 10, %idreg; \
 	or       %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
-	add      %dest_reg, %idreg, %idreg; \
-	ld       [%idreg], %dest_reg;
+	and      %idreg, 0xc, %idreg; \
+	ld       [%idreg + %dest_reg], %dest_reg;
 #else
 #define LOAD_CURRENT(dest_reg, idreg) \
         sethi    %hi(C_LABEL(current_set)), %idreg; \
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.1.36/linux/include/asm-sparc64/asm_offsets.h	Mon Apr 14 16:28:21 1997
+++ linux/include/asm-sparc64/asm_offsets.h	Mon May 12 10:35:43 1997
@@ -64,150 +64,158 @@
 #define ASIZ_task_p_ysptr	0x00000008
 #define AOFF_task_p_osptr	0x00000188
 #define ASIZ_task_p_osptr	0x00000008
-#define AOFF_task_wait_chldexit	0x00000190
+#define AOFF_task_pidhash_next	0x00000190
+#define ASIZ_task_pidhash_next	0x00000008
+#define AOFF_task_pidhash_pprev	0x00000198
+#define ASIZ_task_pidhash_pprev	0x00000008
+#define AOFF_task_tarray_ptr	0x000001a0
+#define ASIZ_task_tarray_ptr	0x00000008
+#define AOFF_task_wait_chldexit	0x000001a8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_uid	0x00000198
+#define AOFF_task_uid	0x000001b0
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x0000019a
+#define AOFF_task_euid	0x000001b2
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x0000019c
+#define AOFF_task_suid	0x000001b4
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x0000019e
+#define AOFF_task_fsuid	0x000001b6
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x000001a0
+#define AOFF_task_gid	0x000001b8
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x000001a2
+#define AOFF_task_egid	0x000001ba
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x000001a4
+#define AOFF_task_sgid	0x000001bc
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x000001a6
+#define AOFF_task_fsgid	0x000001be
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_timeout	0x000001a8
+#define AOFF_task_timeout	0x000001c0
 #define ASIZ_task_timeout	0x00000008
-#define AOFF_task_policy	0x000001b0
+#define AOFF_task_policy	0x000001c8
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x000001b8
+#define AOFF_task_rt_priority	0x000001d0
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x000001c0
+#define AOFF_task_it_real_value	0x000001d8
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x000001c8
+#define AOFF_task_it_prof_value	0x000001e0
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x000001d0
+#define AOFF_task_it_virt_value	0x000001e8
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x000001d8
+#define AOFF_task_it_real_incr	0x000001f0
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x000001e0
+#define AOFF_task_it_prof_incr	0x000001f8
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x000001e8
+#define AOFF_task_it_virt_incr	0x00000200
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x000001f0
+#define AOFF_task_real_timer	0x00000208
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_utime	0x00000218
+#define AOFF_task_utime	0x00000230
 #define ASIZ_task_utime	0x00000008
-#define AOFF_task_stime	0x00000220
+#define AOFF_task_stime	0x00000238
 #define ASIZ_task_stime	0x00000008
-#define AOFF_task_cutime	0x00000228
+#define AOFF_task_cutime	0x00000240
 #define ASIZ_task_cutime	0x00000008
-#define AOFF_task_cstime	0x00000230
+#define AOFF_task_cstime	0x00000248
 #define ASIZ_task_cstime	0x00000008
-#define AOFF_task_start_time	0x00000238
+#define AOFF_task_start_time	0x00000250
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_min_flt	0x00000240
+#define AOFF_task_min_flt	0x00000258
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000248
+#define AOFF_task_maj_flt	0x00000260
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x00000250
+#define AOFF_task_nswap	0x00000268
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x00000258
+#define AOFF_task_cmin_flt	0x00000270
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x00000260
+#define AOFF_task_cmaj_flt	0x00000278
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x00000268
+#define AOFF_task_cnswap	0x00000280
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_swap_address	0x00000278
+#define AOFF_task_swap_address	0x00000290
 #define ASIZ_task_swap_address	0x00000008
-#define AOFF_task_old_maj_flt	0x00000280
+#define AOFF_task_old_maj_flt	0x00000298
 #define ASIZ_task_old_maj_flt	0x00000008
-#define AOFF_task_dec_flt	0x00000288
+#define AOFF_task_dec_flt	0x000002a0
 #define ASIZ_task_dec_flt	0x00000008
-#define AOFF_task_swap_cnt	0x00000290
+#define AOFF_task_swap_cnt	0x000002a8
 #define ASIZ_task_swap_cnt	0x00000008
-#define AOFF_task_rlim	0x00000298
+#define AOFF_task_rlim	0x000002b0
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000338
+#define AOFF_task_used_math	0x00000350
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000033a
+#define AOFF_task_comm	0x00000352
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000034c
+#define AOFF_task_link_count	0x00000364
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000350
+#define AOFF_task_tty	0x00000368
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000358
+#define AOFF_task_semundo	0x00000370
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000360
+#define AOFF_task_semsleeping	0x00000378
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_ldt	0x00000368
+#define AOFF_task_ldt	0x00000380
 #define ASIZ_task_ldt	0x00000008
-#define AOFF_task_tss	0x00000380
+#define AOFF_task_tss	0x000003c0
 #define ASIZ_task_tss	0x00000600
-#define AOFF_task_fs	0x00000980
+#define AOFF_task_fs	0x000009c0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x00000988
+#define AOFF_task_files	0x000009c8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x00000990
+#define AOFF_task_mm	0x000009d0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sig	0x00000998
+#define AOFF_task_sig	0x000009d8
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_processor	0x000009a0
+#define AOFF_task_processor	0x000009e0
 #define ASIZ_task_processor	0x00000004
-#define AOFF_task_last_processor	0x000009a4
+#define AOFF_task_last_processor	0x000009e4
 #define ASIZ_task_last_processor	0x00000004
-#define AOFF_task_lock_depth	0x000009a8
+#define AOFF_task_lock_depth	0x000009e8
 #define ASIZ_task_lock_depth	0x00000004
-#define AOFF_mm_count	0x00000000
-#define ASIZ_mm_count	0x00000004
-#define AOFF_mm_pgd	0x00000008
+#define AOFF_task_sigmask_lock	0x000009ec
+#define ASIZ_task_sigmask_lock	0x00000000
+#define AOFF_mm_mmap	0x00000000
+#define ASIZ_mm_mmap	0x00000008
+#define AOFF_mm_mmap_cache	0x00000008
+#define ASIZ_mm_mmap_cache	0x00000008
+#define AOFF_mm_pgd	0x00000010
 #define ASIZ_mm_pgd	0x00000008
-#define AOFF_mm_context	0x00000010
+#define AOFF_mm_count	0x00000018
+#define ASIZ_mm_count	0x00000004
+#define AOFF_mm_mmap_sem	0x00000020
+#define ASIZ_mm_mmap_sem	0x00000010
+#define AOFF_mm_context	0x00000030
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000018
+#define AOFF_mm_start_code	0x00000038
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000020
+#define AOFF_mm_end_code	0x00000040
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000028
+#define AOFF_mm_start_data	0x00000048
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000030
+#define AOFF_mm_end_data	0x00000050
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000038
+#define AOFF_mm_start_brk	0x00000058
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000040
+#define AOFF_mm_brk	0x00000060
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x00000048
+#define AOFF_mm_start_stack	0x00000068
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_start_mmap	0x00000050
+#define AOFF_mm_start_mmap	0x00000070
 #define ASIZ_mm_start_mmap	0x00000008
-#define AOFF_mm_arg_start	0x00000058
+#define AOFF_mm_arg_start	0x00000078
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x00000060
+#define AOFF_mm_arg_end	0x00000080
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x00000068
+#define AOFF_mm_env_start	0x00000088
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x00000070
+#define AOFF_mm_env_end	0x00000090
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x00000078
+#define AOFF_mm_rss	0x00000098
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x00000080
+#define AOFF_mm_total_vm	0x000000a0
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x00000088
+#define AOFF_mm_locked_vm	0x000000a8
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x00000090
+#define AOFF_mm_def_flags	0x000000b0
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_mmap	0x00000098
-#define ASIZ_mm_mmap	0x00000008
-#define AOFF_mm_mmap_avl	0x000000a0
-#define ASIZ_mm_mmap_avl	0x00000008
-#define AOFF_mm_mmap_sem	0x000000a8
-#define ASIZ_mm_mmap_sem	0x00000010
 #define AOFF_thread_float_regs	0x00000000
 #define ASIZ_thread_float_regs	0x00000100
 #define AOFF_thread_fsr	0x00000100
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/fs_mount.h linux/include/asm-sparc64/fs_mount.h
--- v2.1.36/linux/include/asm-sparc64/fs_mount.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/fs_mount.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,44 @@
+/* $Id: fs_mount.h,v 1.2 1997/04/18 14:34:46 jj Exp $
+ * fs_mount.h:  Definitions for mount structure conversions.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+ 
+#ifndef __ASM_FS_MOUNT_H
+#define __ASM_FS_MOUNT_H
+
+#if defined(CONFIG_SPARC32_COMPAT) || defined(CONFIG_SPARC32_COMPAT_MODULE)
+
+#include <linux/sched.h>
+
+/* We need this to convert 32bit mount structures to 64bit */
+
+extern void *do_ncp_super_data_conv(void *raw_data);
+extern void *do_smb_super_data_conv(void *raw_data);
+
+extern __inline__ void *ncp_super_data_conv(void *raw_data)
+{
+	if (current->tss.flags & SPARC_FLAG_32BIT)
+		return do_ncp_super_data_conv(raw_data);
+	else
+		return raw_data;
+}
+
+extern __inline__ void *smb_super_data_conv(void *raw_data)
+{
+	if (current->tss.flags & SPARC_FLAG_32BIT)
+		return do_smb_super_data_conv(raw_data);
+	else
+		return raw_data;
+}
+
+#else /* CONFIG_SPARC32_COMPAT* */
+
+#define ncp_super_data_conv(__x) __x
+#define smb_super_data_conv(__x) __x
+
+#endif /* CONFIG_SPARC32_COMPAT* */
+
+#define nfs_super_data_conv(__x) __x
+
+#endif /* __ASM_FS_MOUNT_H */
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.36/linux/include/asm-sparc64/head.h	Mon Apr 14 16:28:22 1997
+++ linux/include/asm-sparc64/head.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.16 1997/04/08 11:03:13 davem Exp $ */
+/* $Id: head.h,v 1.17 1997/04/28 14:57:13 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
@@ -113,7 +113,7 @@
 #define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
 
 #define TRAP_IRQ(routine, level)			\
-	rdpr	%pil, %g4;				\
+	rdpr	%pil, %g2;				\
 	wrpr	%g0, 15, %pil;				\
 	ba,pt	%xcc, etrap_irq;			\
 	 rd	%pc, %g7;				\
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/linux_logo.h linux/include/asm-sparc64/linux_logo.h
--- v2.1.36/linux/include/asm-sparc64/linux_logo.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/linux_logo.h	Mon May 12 10:35:43 1997
@@ -1040,1045 +1040,3 @@
 "'!!!!!!!W..e$$!!!!!!`    %s\n"
 " \"~^^~         ^~~^\n"
 "\n";
-/* $Id: linux_logo.h,v 1.1 1997/04/16 17:51:37 jj Exp $
- * include/asm-sparc64/linux_logo.h: This is a linux logo
- *                                   to be displayed on boot.
- *
- * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * You can put anything here, but:
- * LINUX_LOGO_COLORS has to be less than 224
- * image size has to be 80x80
- * values have to start from 0x20
- * (i.e. RGB(linux_logo_red[0],
- *	     linux_logo_green[0],
- *	     linux_logo_blue[0]) is color 0x20)
- * BW image has to be 80x80 as well, with MS bit
- * on the left
- * Serial_console ascii image can be any size,
- * but should contain %s to display the version
- */
- 
-#include <linux/init.h>
-#include <linux/version.h>
-
-#define linux_logo_banner "Linux/UltraSPARC version " UTS_RELEASE
-
-#define LINUX_LOGO_COLORS 215
-
-unsigned char linux_logo_red[] __initdata = {
-  0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0x02, 0x00,
-  0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x3B, 0x25,
-  0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xB0,
-  0x0C, 0xB1, 0xD4, 0xCE, 0x04, 0x06, 0x16, 0xB6,
-  0xCD, 0xB2, 0x42, 0x46, 0x4B, 0xA8, 0xF3, 0xCA,
-  0xC5, 0x1C, 0xDC, 0xA0, 0xD4, 0xE6, 0xED, 0xF3,
-  0xC2, 0x8E, 0xCC, 0xA5, 0x7E, 0x52, 0xF7, 0xE3,
-  0x56, 0x79, 0x68, 0x8D, 0xAF, 0xFC, 0x8E, 0x3E,
-  0x6B, 0x11, 0x37, 0x79, 0x5C, 0x3C, 0x3F, 0x3C,
-  0x48, 0x47, 0x3D, 0xB9, 0x62, 0xE1, 0x4D, 0x57,
-  0x84, 0x78, 0xA6, 0x58, 0x99, 0xCD, 0xB7, 0xE3,
-  0x6D, 0x5A, 0xAF, 0x79, 0x79, 0xF2, 0x42, 0x46,
-  0xDD, 0x89, 0xC3, 0xF2, 0xF0, 0xE0, 0xD1, 0x90,
-  0x76, 0x6B, 0x4A, 0xBE, 0xBD, 0xE3, 0xF6, 0xE9,
-  0xEC, 0xE8, 0xEC, 0xC0, 0x66, 0x63, 0xCB, 0xAB,
-  0x49, 0x5C, 0xAD, 0xD6, 0xEE, 0xF5, 0xF5, 0xE9,
-  0x6E, 0x00, 0x69, 0x6A, 0xA1, 0x7A, 0xB4, 0xDE,
-  0xF1, 0xF6, 0xDD, 0x00, 0x73, 0xDB, 0x4C, 0x53,
-  0x6A, 0xF5, 0xF5, 0xD6, 0xC3, 0x6A, 0x4B, 0x4B,
-  0x60, 0xF8, 0x9B, 0xD7, 0xD7, 0x71, 0xB3, 0xA4,
-  0xCA, 0xAB, 0xB4, 0xB2, 0x76, 0xBA, 0x8B, 0xA0,
-  0xA5, 0xEE, 0xE7, 0x67, 0x5F, 0x08, 0x94, 0xDB,
-  0xE5, 0x4F, 0x00, 0x34, 0xEE, 0xEC, 0xE2, 0x48,
-  0xF3, 0xEB, 0xF4, 0xF4, 0xEF, 0xD6, 0xB6, 0xE6,
-  0xE6, 0xED, 0xE7, 0xE6, 0x3D, 0xE7, 0xCD, 0x44,
-  0xEF, 0xEC, 0xF5, 0x66, 0xF3, 0xA9, 0x77, 0x58,
-  0x75, 0x6C, 0x53, 0x24, 0xAC, 0x0D, 0x3C
-};
-
-unsigned char linux_logo_green[] __initdata = {
-  0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0x02, 0x00,
-  0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x3B, 0x25,
-  0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xAD,
-  0x0C, 0xB1, 0x92, 0xAB, 0x03, 0x06, 0x16, 0xB6,
-  0xCD, 0x88, 0x42, 0x46, 0x4B, 0x94, 0xBB, 0xCA,
-  0xC5, 0x1C, 0xAB, 0xA0, 0xD4, 0xE6, 0xED, 0xF3,
-  0xC2, 0x73, 0xCA, 0x91, 0x7E, 0x52, 0xF7, 0xE3,
-  0x56, 0x5A, 0x49, 0x56, 0x6E, 0xFC, 0x6B, 0x3E,
-  0x6B, 0x0D, 0x37, 0x79, 0x51, 0x44, 0x3F, 0x43,
-  0x38, 0x3D, 0x48, 0xB9, 0x62, 0xA5, 0x47, 0x48,
-  0x49, 0x4A, 0x97, 0x48, 0x81, 0x95, 0x8E, 0xE3,
-  0x6D, 0x57, 0x51, 0x51, 0x47, 0xB2, 0x42, 0x46,
-  0xDD, 0x5B, 0x87, 0xBE, 0xC7, 0xC8, 0x56, 0x75,
-  0x5D, 0x4B, 0x4D, 0xBE, 0x85, 0xA6, 0xBC, 0xC7,
-  0xCA, 0xCD, 0xCC, 0xA4, 0x53, 0x4D, 0x9F, 0x55,
-  0x52, 0x5E, 0x75, 0x9C, 0xB6, 0xC3, 0xD7, 0xCC,
-  0x55, 0x00, 0x6A, 0x59, 0x7D, 0x55, 0x7C, 0xA3,
-  0xB7, 0xBF, 0xA5, 0x00, 0x67, 0xC6, 0x47, 0x54,
-  0x46, 0xB8, 0xBE, 0xB2, 0x87, 0x52, 0x4B, 0x43,
-  0x41, 0xF8, 0x69, 0x96, 0x9B, 0x66, 0xB0, 0x6C,
-  0x8E, 0x81, 0xB4, 0x76, 0x76, 0xB9, 0x65, 0x77,
-  0x6D, 0xED, 0xE7, 0x67, 0x5F, 0x06, 0x54, 0x6C,
-  0xCB, 0x4F, 0x00, 0x2F, 0xC2, 0xB5, 0xB6, 0x30,
-  0xC3, 0xAE, 0xC4, 0xCA, 0xC6, 0xB4, 0x7B, 0xAD,
-  0xAD, 0xB6, 0xB6, 0xAD, 0x29, 0xAB, 0x93, 0x2E,
-  0xBC, 0xBC, 0xC9, 0x53, 0xBF, 0x77, 0x54, 0x3B,
-  0x4B, 0x3F, 0x39, 0x19, 0x76, 0x08, 0x2C
-};
-
-unsigned char linux_logo_blue[] __initdata = {
-  0x99, 0x95, 0x92, 0x8E, 0x8A, 0x86, 0xD6, 0x00,
-  0xA5, 0xA9, 0xA2, 0x9E, 0xAD, 0x1B, 0x39, 0x25,
-  0x71, 0x65, 0x2C, 0x82, 0x5B, 0x33, 0x13, 0xA7,
-  0x0C, 0xB1, 0x58, 0x8A, 0x03, 0x07, 0x16, 0xB6,
-  0xCD, 0x5A, 0x42, 0x46, 0x4F, 0x6F, 0x77, 0xCA,
-  0xC5, 0x1C, 0x6F, 0xA5, 0xD4, 0xE6, 0xF5, 0xF3,
-  0xC2, 0x4D, 0xD1, 0x64, 0x7E, 0x52, 0xF7, 0xE3,
-  0x56, 0x49, 0x3C, 0x47, 0x45, 0xFE, 0x3B, 0x41,
-  0x6B, 0x09, 0x37, 0x79, 0x39, 0x39, 0x3F, 0x42,
-  0x3A, 0x42, 0x5F, 0xB9, 0x62, 0x4C, 0x39, 0x44,
-  0x3B, 0x3A, 0xA0, 0x3D, 0x08, 0x08, 0x09, 0xDE,
-  0x6D, 0x48, 0x3B, 0x3F, 0x42, 0xF3, 0x36, 0x3C,
-  0xDD, 0x06, 0x16, 0x08, 0x13, 0x0A, 0x4B, 0x71,
-  0x5D, 0x44, 0x47, 0xBE, 0x08, 0x0C, 0x0D, 0x0C,
-  0x19, 0x29, 0x36, 0x06, 0x43, 0x44, 0xBA, 0x45,
-  0x50, 0x58, 0x07, 0x07, 0x0D, 0x0E, 0x10, 0x50,
-  0x06, 0x42, 0x40, 0x44, 0x79, 0x06, 0x06, 0x0C,
-  0x08, 0x08, 0x07, 0x36, 0x4C, 0xE5, 0x42, 0x55,
-  0x03, 0x0F, 0x12, 0x06, 0x07, 0x3C, 0x4B, 0x3D,
-  0x01, 0xF8, 0x08, 0x0E, 0x0A, 0x69, 0xAC, 0x0C,
-  0x0A, 0x27, 0xBB, 0x36, 0x76, 0xC0, 0x04, 0x08,
-  0x08, 0xED, 0xEE, 0x68, 0x5F, 0xB2, 0x3B, 0x52,
-  0xAC, 0x4F, 0x6F, 0x2D, 0x16, 0x08, 0x59, 0x04,
-  0x13, 0x0E, 0x14, 0x17, 0x16, 0x2E, 0x08, 0x0D,
-  0x11, 0x14, 0x0D, 0x06, 0x04, 0x08, 0x25, 0x8E,
-  0x0E, 0x14, 0x25, 0x9B, 0x1C, 0x16, 0x78, 0x06,
-  0x04, 0x03, 0x79, 0x8C, 0x0B, 0xC8, 0x48
-};
-
-unsigned char linux_logo[] __initdata = {
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24,
-  0x25, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25,
-  0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x23,
-  0x23, 0x22, 0x22, 0x22, 0x22, 0x21, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x26, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x28,
-  0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
-  0x29, 0x28, 0x28, 0x28, 0x2A, 0x2A, 0x2B, 0x2B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x2B, 0x2B, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29,
-  0x29, 0x29, 0x29, 0x2C, 0x29, 0x29, 0x29, 0x28,
-  0x28, 0x2A, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B, 0x2A, 0x2A,
-  0x2A, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x2D, 0x2E, 0x2F, 0x27,
-  0x27, 0x26, 0x2B, 0x2A, 0x2A, 0x2A, 0x2A, 0x28,
-  0x28, 0x29, 0x29, 0x29, 0x29, 0x2C, 0x2C, 0x29,
-  0x29, 0x29, 0x28, 0x28, 0x2A, 0x2B, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2A, 0x2A, 0x2A,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x2F, 0x30, 0x31, 0x32,
-  0x27, 0x27, 0x22, 0x22, 0x22, 0x22, 0x21, 0x20,
-  0x20, 0x20, 0x2B, 0x2A, 0x28, 0x29, 0x29, 0x29,
-  0x2C, 0x2C, 0x2C, 0x29, 0x29, 0x28, 0x2A, 0x2B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x32, 0x33, 0x34, 0x35,
-  0x36, 0x27, 0x27, 0x33, 0x25, 0x25, 0x24, 0x24,
-  0x24, 0x24, 0x23, 0x21, 0x20, 0x20, 0x2B, 0x2A,
-  0x28, 0x29, 0x29, 0x37, 0x2C, 0x2C, 0x29, 0x28,
-  0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B,
-  0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2A, 0x2B, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x2F, 0x32, 0x36, 0x27,
-  0x27, 0x27, 0x27, 0x33, 0x33, 0x33, 0x33, 0x33,
-  0x33, 0x33, 0x33, 0x25, 0x25, 0x24, 0x23, 0x21,
-  0x20, 0x2B, 0x2A, 0x29, 0x29, 0x2C, 0x2C, 0x2C,
-  0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B,
-  0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x21, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x38, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x23, 0x23, 0x24, 0x24,
-  0x25, 0x25, 0x33, 0x33, 0x33, 0x33, 0x33, 0x25,
-  0x24, 0x22, 0x20, 0x20, 0x2A, 0x28, 0x29, 0x2C,
-  0x2C, 0x2C, 0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B,
-  0x2B, 0x2B, 0x2B, 0x20, 0x21, 0x22, 0x23, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x2A, 0x2A, 0x2B, 0x2B,
-  0x20, 0x21, 0x22, 0x24, 0x20, 0x39, 0x39, 0x39,
-  0x39, 0x39, 0x3A, 0x3B, 0x22, 0x20, 0x2A, 0x28,
-  0x29, 0x2C, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
-  0x2B, 0x20, 0x21, 0x22, 0x22, 0x23, 0x24, 0x27,
-  0x27, 0x27, 0x3C, 0x36, 0x3C, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x3D, 0x3E, 0x32, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x3D, 0x39, 0x3F, 0x3F,
-  0x39, 0x2C, 0x20, 0x20, 0x39, 0x39, 0x39, 0x39,
-  0x39, 0x39, 0x39, 0x40, 0x40, 0x41, 0x22, 0x20,
-  0x2A, 0x28, 0x2C, 0x2C, 0x2C, 0x29, 0x29, 0x2A,
-  0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x20,
-  0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x22, 0x27,
-  0x27, 0x3C, 0x3C, 0x3D, 0x42, 0x3C, 0x27, 0x27,
-  0x3C, 0x27, 0x3C, 0x43, 0x44, 0x36, 0x42, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x3D, 0x28, 0x29, 0x2C,
-  0x2C, 0x45, 0x20, 0x39, 0x39, 0x39, 0x39, 0x39,
-  0x39, 0x46, 0x40, 0x47, 0x40, 0x47, 0x3A, 0x40,
-  0x22, 0x20, 0x2A, 0x29, 0x2C, 0x2C, 0x2C, 0x29,
-  0x28, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x2B, 0x2B, 0x2B, 0x2B, 0x20, 0x20, 0x22,
-  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x20, 0x27,
-  0x27, 0x44, 0x28, 0x24, 0x27, 0x2F, 0x3C, 0x27,
-  0x27, 0x38, 0x24, 0x2C, 0x2C, 0x48, 0x49, 0x36,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x29, 0x29,
-  0x4A, 0x20, 0x3A, 0x40, 0x47, 0x40, 0x47, 0x40,
-  0x40, 0x47, 0x40, 0x40, 0x39, 0x39, 0x39, 0x4A,
-  0x25, 0x24, 0x22, 0x2B, 0x28, 0x29, 0x2C, 0x2C,
-  0x29, 0x28, 0x2A, 0x2B, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x2B, 0x2B, 0x20, 0x20, 0x20, 0x21, 0x22, 0x22,
-  0x22, 0x22, 0x22, 0x21, 0x20, 0x2B, 0x2A, 0x27,
-  0x3D, 0x4B, 0x48, 0x4C, 0x2B, 0x3C, 0x27, 0x3C,
-  0x3C, 0x23, 0x4D, 0x4E, 0x4F, 0x50, 0x33, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x39, 0x3F, 0x39,
-  0x51, 0x20, 0x39, 0x39, 0x47, 0x40, 0x4D, 0x4D,
-  0x40, 0x52, 0x4D, 0x40, 0x47, 0x40, 0x39, 0x39,
-  0x53, 0x54, 0x25, 0x24, 0x20, 0x2A, 0x29, 0x2C,
-  0x2C, 0x2C, 0x29, 0x2A, 0x2B, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
-  0x22, 0x21, 0x20, 0x2B, 0x28, 0x2A, 0x20, 0x27,
-  0x36, 0x4F, 0x55, 0x48, 0x56, 0x3D, 0x3C, 0x3C,
-  0x32, 0x57, 0x56, 0x58, 0x49, 0x56, 0x56, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x22, 0x20, 0x20,
-  0x41, 0x39, 0x39, 0x3A, 0x59, 0x5A, 0x59, 0x5B,
-  0x5C, 0x3A, 0x4D, 0x5D, 0x57, 0x39, 0x39, 0x4A,
-  0x5E, 0x33, 0x54, 0x33, 0x24, 0x22, 0x2B, 0x28,
-  0x2C, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21,
-  0x20, 0x2B, 0x2A, 0x2A, 0x20, 0x22, 0x22, 0x27,
-  0x5F, 0x2D, 0x3C, 0x60, 0x56, 0x54, 0x61, 0x49,
-  0x35, 0x56, 0x34, 0x27, 0x62, 0x27, 0x56, 0x39,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x63, 0x54,
-  0x40, 0x64, 0x65, 0x66, 0x67, 0x67, 0x68, 0x5F,
-  0x2E, 0x69, 0x6A, 0x67, 0x5F, 0x3A, 0x39, 0x2C,
-  0x53, 0x23, 0x25, 0x54, 0x33, 0x25, 0x23, 0x20,
-  0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28, 0x2B, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20,
-  0x2B, 0x2A, 0x20, 0x22, 0x22, 0x21, 0x2B, 0x27,
-  0x62, 0x36, 0x27, 0x33, 0x6B, 0x54, 0x3D, 0x3C,
-  0x49, 0x57, 0x27, 0x27, 0x27, 0x27, 0x56, 0x57,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x6C, 0x31, 0x6D,
-  0x64, 0x51, 0x6E, 0x2E, 0x2E, 0x6F, 0x5A, 0x70,
-  0x70, 0x71, 0x72, 0x67, 0x67, 0x69, 0x73, 0x46,
-  0x4A, 0x2A, 0x21, 0x25, 0x33, 0x54, 0x33, 0x24,
-  0x20, 0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28, 0x2B,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x2B,
-  0x2B, 0x22, 0x22, 0x22, 0x2B, 0x28, 0x2A, 0x27,
-  0x27, 0x39, 0x3C, 0x3D, 0x45, 0x74, 0x75, 0x76,
-  0x76, 0x45, 0x27, 0x27, 0x27, 0x27, 0x56, 0x77,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x78, 0x78, 0x5E,
-  0x79, 0x7A, 0x7B, 0x6E, 0x5A, 0x5A, 0x70, 0x7C,
-  0x70, 0x5B, 0x7D, 0x5A, 0x66, 0x7E, 0x7F, 0x79,
-  0x48, 0x6B, 0x2C, 0x20, 0x24, 0x33, 0x54, 0x33,
-  0x24, 0x21, 0x2A, 0x29, 0x2C, 0x2C, 0x29, 0x28,
-  0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x21, 0x21, 0x21, 0x20, 0x20, 0x2B, 0x2B, 0x21,
-  0x22, 0x22, 0x20, 0x28, 0x2B, 0x20, 0x22, 0x27,
-  0x27, 0x80, 0x27, 0x81, 0x82, 0x83, 0x84, 0x85,
-  0x74, 0x85, 0x84, 0x27, 0x3C, 0x4F, 0x4F, 0x66,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x22, 0x23, 0x5E,
-  0x64, 0x86, 0x79, 0x73, 0x87, 0x88, 0x7C, 0x5A,
-  0x5A, 0x71, 0x7D, 0x71, 0x89, 0x79, 0x8A, 0x8A,
-  0x51, 0x8B, 0x48, 0x39, 0x2A, 0x22, 0x33, 0x54,
-  0x33, 0x25, 0x22, 0x2B, 0x29, 0x2C, 0x2C, 0x29,
-  0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x21, 0x21, 0x20, 0x20, 0x2B, 0x2B, 0x22, 0x23,
-  0x21, 0x2A, 0x2A, 0x20, 0x21, 0x23, 0x25, 0x27,
-  0x27, 0x55, 0x8C, 0x8D, 0x8E, 0x83, 0x8F, 0x90,
-  0x91, 0x92, 0x92, 0x85, 0x85, 0x93, 0x51, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0x29, 0x51,
-  0x79, 0x79, 0x94, 0x89, 0x89, 0x89, 0x5A, 0x95,
-  0x64, 0x88, 0x96, 0x97, 0x7A, 0x73, 0x98, 0x98,
-  0x99, 0x50, 0x50, 0x48, 0x6B, 0x28, 0x21, 0x25,
-  0x54, 0x54, 0x25, 0x22, 0x2B, 0x29, 0x2C, 0x29,
-  0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x2B, 0x20, 0x22, 0x22, 0x20,
-  0x2B, 0x2B, 0x20, 0x22, 0x24, 0x25, 0x33, 0x27,
-  0x27, 0x9A, 0x9B, 0x9C, 0x9D, 0x83, 0x9E, 0x85,
-  0x9F, 0x92, 0x85, 0x85, 0x85, 0x85, 0x92, 0xA0,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0xA1, 0x47, 0xA2,
-  0xA2, 0x94, 0xA3, 0x94, 0x95, 0x95, 0x73, 0x73,
-  0x95, 0x87, 0xA4, 0x5B, 0x97, 0x7B, 0x88, 0x98,
-  0xA2, 0x50, 0x48, 0x48, 0x48, 0x8B, 0x29, 0x20,
-  0x25, 0x54, 0x54, 0x25, 0x22, 0x2B, 0x29, 0x29,
-  0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x2B, 0x2B,
-  0x20, 0x21, 0x23, 0x24, 0x25, 0x25, 0x33, 0x27,
-  0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x8F, 0x90, 0x90,
-  0x9F, 0x90, 0x85, 0x90, 0x85, 0x74, 0xAA, 0x81,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0xAB, 0x40, 0xAC,
-  0x79, 0xA3, 0x89, 0xAD, 0x95, 0x6F, 0xAE, 0xAE,
-  0xAE, 0x5B, 0x59, 0x88, 0x7B, 0x89, 0x79, 0xAF,
-  0xA2, 0x6B, 0x48, 0x48, 0x48, 0x48, 0x50, 0x2C,
-  0x20, 0x24, 0x33, 0x54, 0x25, 0x22, 0x2A, 0x2A,
-  0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x21, 0x23, 0x22, 0x2B, 0x20, 0x20,
-  0x22, 0x23, 0x24, 0x25, 0x24, 0x24, 0x22, 0x27,
-  0xB0, 0x8C, 0xAA, 0xB1, 0xB2, 0x84, 0x85, 0x9F,
-  0x85, 0x85, 0x85, 0xB3, 0xB4, 0xAA, 0xAA, 0xA0,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2A, 0xB5,
-  0xA3, 0xA3, 0xAC, 0x5D, 0xB6, 0xAE, 0xB7, 0x69,
-  0x73, 0x5B, 0x88, 0x89, 0x95, 0x73, 0x99, 0x99,
-  0x59, 0x2A, 0x39, 0x48, 0x48, 0x50, 0x48, 0x50,
-  0x2C, 0x20, 0x24, 0x33, 0x54, 0x25, 0x21, 0x20,
-  0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x21, 0x23, 0x21, 0x2B, 0x20, 0x20, 0x22,
-  0x22, 0x24, 0x24, 0x23, 0x22, 0x20, 0x2A, 0x27,
-  0x27, 0xB0, 0x8C, 0xA9, 0xB2, 0x9E, 0x91, 0x85,
-  0x85, 0x93, 0xB8, 0x75, 0xAA, 0xA7, 0x8C, 0x27,
-  0x27, 0x27, 0x33, 0x3C, 0x27, 0x27, 0x2C, 0x7B,
-  0x55, 0x79, 0xA3, 0x5D, 0xB9, 0x43, 0x7F, 0x7E,
-  0x5F, 0x5A, 0x5A, 0x95, 0x64, 0x73, 0x58, 0x64,
-  0x5C, 0x25, 0x2B, 0x3F, 0x48, 0x48, 0x8B, 0x48,
-  0x48, 0x2C, 0x20, 0x25, 0x54, 0x33, 0x24, 0x22,
-  0x2B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x21, 0x23, 0x21, 0x20, 0x20, 0x20, 0x21, 0x22,
-  0x24, 0x23, 0x22, 0x21, 0x2B, 0x20, 0x54, 0x27,
-  0x27, 0x8B, 0x81, 0xA5, 0x93, 0x93, 0x74, 0xA5,
-  0xBA, 0x75, 0xBB, 0xBC, 0xB4, 0x6D, 0x50, 0x6B,
-  0x27, 0x27, 0x30, 0x33, 0x49, 0x27, 0x27, 0x5E,
-  0x6F, 0x73, 0x94, 0xBD, 0x4E, 0x5D, 0x7F, 0x7F,
-  0xB7, 0x68, 0x73, 0x6E, 0xB7, 0x7F, 0x95, 0x97,
-  0x47, 0x63, 0x25, 0x20, 0x3F, 0x48, 0x8B, 0x8B,
-  0x48, 0x48, 0x2C, 0x20, 0x25, 0x54, 0x33, 0x25,
-  0x2B, 0x2B, 0x2B, 0x20, 0x20, 0x20, 0x21, 0x21,
-  0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24,
-  0x22, 0x21, 0x20, 0x2A, 0x33, 0x30, 0x30, 0x27,
-  0x27, 0x50, 0xBE, 0xBF, 0x9A, 0xB3, 0x9B, 0xBB,
-  0xBB, 0xC0, 0x8C, 0xC1, 0x8B, 0xC2, 0x47, 0x8B,
-  0x27, 0x27, 0x38, 0x63, 0x63, 0x27, 0x27, 0xC3,
-  0xB5, 0x95, 0x72, 0x95, 0x6F, 0x69, 0x7E, 0x66,
-  0x7E, 0x7F, 0x6E, 0x7E, 0x95, 0x95, 0x73, 0x70,
-  0x30, 0x30, 0x30, 0x33, 0x20, 0x3F, 0x48, 0x8B,
-  0x6B, 0x48, 0x50, 0x29, 0x21, 0x33, 0x54, 0x33,
-  0x2A, 0x2B, 0x2B, 0x20, 0x20, 0x21, 0x21, 0x23,
-  0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24, 0x22,
-  0x20, 0x2B, 0x21, 0xC4, 0x30, 0x60, 0x30, 0x27,
-  0x27, 0xC5, 0x8B, 0x39, 0xC6, 0xC7, 0xA6, 0xA6,
-  0xC8, 0x9A, 0x3B, 0x39, 0x50, 0x56, 0x56, 0x4F,
-  0x33, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x48,
-  0x59, 0x94, 0x73, 0xAE, 0xB7, 0xB7, 0x7E, 0x7E,
-  0x7E, 0x7E, 0x7E, 0x5A, 0x70, 0x7C, 0x71, 0xC3,
-  0x63, 0x30, 0x60, 0x78, 0x54, 0x20, 0x6B, 0x48,
-  0x6B, 0x6B, 0x50, 0x50, 0x29, 0x22, 0x33, 0x33,
-  0x2A, 0x2B, 0x20, 0x20, 0x21, 0x22, 0x22, 0x22,
-  0x21, 0x20, 0x20, 0x20, 0x24, 0x24, 0x20, 0x20,
-  0x2B, 0x24, 0x30, 0x60, 0x60, 0x30, 0xAB, 0x27,
-  0x27, 0x40, 0x4C, 0x50, 0x39, 0x87, 0xC3, 0x53,
-  0x37, 0x48, 0x37, 0x48, 0xC9, 0x56, 0xB9, 0x56,
-  0xCA, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x3C,
-  0x51, 0x5A, 0x6E, 0xB7, 0xB7, 0x7E, 0x7E, 0x7E,
-  0x7E, 0x7E, 0x7F, 0xB7, 0x5A, 0x7C, 0x5B, 0x37,
-  0x23, 0x63, 0x31, 0x6C, 0xCB, 0x63, 0x20, 0x6B,
-  0x50, 0x3F, 0x39, 0x50, 0x8B, 0x28, 0x24, 0x24,
-  0x2B, 0x2B, 0x20, 0x21, 0x22, 0x22, 0x22, 0x21,
-  0x20, 0x20, 0x20, 0x23, 0x23, 0x20, 0x20, 0x2B,
-  0x33, 0x78, 0xCB, 0x60, 0x30, 0x22, 0x3D, 0x27,
-  0x2F, 0x56, 0x4E, 0x8B, 0x6B, 0x39, 0x48, 0x8B,
-  0x6B, 0x8B, 0x80, 0xC9, 0xB9, 0xB9, 0x56, 0xB9,
-  0x56, 0x34, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x48, 0xB5, 0xB7, 0xB7, 0x7E, 0x7E, 0x2E, 0x7E,
-  0x7E, 0x7E, 0x7F, 0x7C, 0x65, 0x71, 0x3A, 0x48,
-  0x2C, 0x24, 0x30, 0x6C, 0x34, 0x6C, 0xC4, 0x20,
-  0x8B, 0x50, 0x39, 0x39, 0x48, 0x6B, 0x2B, 0x22,
-  0x2B, 0x20, 0x21, 0x22, 0x23, 0x23, 0x22, 0x21,
-  0x20, 0x2B, 0x23, 0x22, 0x20, 0x2B, 0x2B, 0x54,
-  0x60, 0x31, 0xCB, 0x54, 0x20, 0x3D, 0x36, 0x27,
-  0x4E, 0xB9, 0x56, 0x56, 0x8B, 0x6B, 0x50, 0x6B,
-  0x40, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9,
-  0x56, 0x56, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x7B, 0x6E, 0xB7, 0xB7, 0xB7, 0x7E, 0x7F,
-  0xB7, 0xB7, 0x7F, 0x7E, 0x6F, 0x5B, 0x29, 0x2C,
-  0x48, 0x39, 0x24, 0x60, 0x58, 0xAF, 0xCC, 0x63,
-  0x20, 0x8B, 0x8B, 0x39, 0x39, 0x48, 0x3F, 0x28,
-  0x20, 0x20, 0x22, 0x23, 0x23, 0x23, 0x22, 0x20,
-  0x2B, 0x22, 0x22, 0x2B, 0x2B, 0x20, 0x54, 0xCB,
-  0x31, 0xCB, 0x25, 0x20, 0x27, 0x27, 0x27, 0x48,
-  0xB9, 0x56, 0xB9, 0x56, 0x4F, 0x48, 0x47, 0x57,
-  0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
-  0xB9, 0x56, 0x62, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x48, 0x6F, 0x69, 0xB7, 0xB7, 0xB7, 0x7F,
-  0xB7, 0xB7, 0xB7, 0x73, 0x59, 0x50, 0x29, 0x2B,
-  0x28, 0x8B, 0x39, 0x25, 0x31, 0x55, 0xB6, 0x34,
-  0x63, 0x2B, 0x48, 0x6B, 0x2C, 0x39, 0x47, 0x6B,
-  0x22, 0x22, 0x23, 0x24, 0x23, 0x22, 0x20, 0x2B,
-  0x20, 0x22, 0x2A, 0x2B, 0x20, 0x33, 0xCB, 0x31,
-  0x78, 0x24, 0x21, 0xCD, 0x27, 0x27, 0x27, 0x56,
-  0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0x56, 0xB9,
-  0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
-  0xB9, 0x56, 0xC9, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x41, 0x64, 0xB7, 0xB7, 0xB7, 0x7F,
-  0x68, 0xB7, 0xAE, 0xA3, 0x23, 0x39, 0x8B, 0x2A,
-  0x20, 0x20, 0x39, 0x6B, 0x25, 0xCC, 0x43, 0x43,
-  0x34, 0x63, 0x2A, 0x48, 0x3F, 0x39, 0x6B, 0x6B,
-  0x24, 0x23, 0x24, 0x24, 0x23, 0x21, 0x2B, 0x2B,
-  0x22, 0x2B, 0x2B, 0x20, 0x24, 0x78, 0x31, 0x30,
-  0x23, 0x21, 0x21, 0x27, 0x27, 0x27, 0x80, 0x56,
-  0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9,
-  0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
-  0x56, 0xB9, 0x56, 0x3C, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xCE, 0x8A, 0xAE, 0x6F, 0xB7,
-  0x6F, 0x89, 0x71, 0x78, 0x63, 0x23, 0x39, 0x6B,
-  0x2B, 0x20, 0x20, 0x2C, 0x6B, 0x25, 0x34, 0x42,
-  0x42, 0x34, 0x54, 0x29, 0x48, 0x3F, 0x39, 0x3F,
-  0x25, 0x24, 0x25, 0x24, 0x22, 0x20, 0x2A, 0x21,
-  0x2B, 0x2A, 0x20, 0x22, 0x30, 0x60, 0x30, 0x22,
-  0x21, 0x22, 0x27, 0x27, 0x27, 0x2D, 0x4C, 0x56,
-  0x56, 0xB9, 0xB9, 0x56, 0xB9, 0xB9, 0x56, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0x56, 0x2E, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x40, 0x97, 0x95, 0x5A, 0x71,
-  0x7C, 0xCE, 0x40, 0x60, 0x31, 0x30, 0x23, 0x3F,
-  0x3F, 0x20, 0x20, 0x20, 0x29, 0x8B, 0x33, 0x58,
-  0x66, 0x43, 0xCC, 0x25, 0x39, 0x50, 0x6B, 0x2C,
-  0x33, 0x25, 0x25, 0x23, 0x20, 0x2A, 0x2B, 0x20,
-  0x2A, 0x2B, 0x22, 0x54, 0x30, 0x30, 0x24, 0x22,
-  0x21, 0x27, 0x27, 0x27, 0x27, 0xAF, 0x29, 0x4E,
-  0x4F, 0xB9, 0x56, 0xB9, 0x4D, 0x4D, 0x77, 0xC9,
-  0xB9, 0xB9, 0xB9, 0x56, 0xC9, 0x4D, 0x4D, 0x80,
-  0x4C, 0x40, 0xC9, 0x4D, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0xCF, 0x97, 0x97, 0xCE,
-  0x86, 0xD0, 0x54, 0x6C, 0x58, 0x34, 0x60, 0x23,
-  0x6B, 0x39, 0x20, 0x20, 0x20, 0x28, 0x6B, 0x54,
-  0xD1, 0x66, 0xB6, 0x60, 0x22, 0x6B, 0x8B, 0x2C,
-  0x54, 0x33, 0x24, 0x22, 0x2B, 0x28, 0x20, 0x28,
-  0x2B, 0x20, 0x25, 0xC4, 0x30, 0x25, 0x22, 0x21,
-  0x26, 0x27, 0x27, 0x27, 0x27, 0x20, 0x4B, 0x52,
-  0x80, 0x4F, 0xB9, 0x56, 0xB9, 0x80, 0x56, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x4D, 0x80, 0x50, 0x48,
-  0x50, 0x50, 0x50, 0x56, 0x3D, 0x27, 0x36, 0x27,
-  0x27, 0x27, 0x27, 0x3C, 0x46, 0xC3, 0x86, 0x86,
-  0xD0, 0x39, 0x24, 0x6C, 0xD1, 0x43, 0x43, 0x6C,
-  0x24, 0x6B, 0x2C, 0x20, 0x20, 0x20, 0x29, 0x39,
-  0x63, 0xD1, 0x42, 0x55, 0xC4, 0x2B, 0x8B, 0x39,
-  0x54, 0x25, 0x24, 0x20, 0x2A, 0x2A, 0x28, 0x28,
-  0x20, 0x22, 0x54, 0x63, 0x25, 0x24, 0x22, 0x22,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x77, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0xC9, 0x56, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x4F,
-  0x77, 0x47, 0x8B, 0x40, 0x56, 0x27, 0x27, 0x49,
-  0x2D, 0x27, 0x27, 0x27, 0x39, 0x40, 0x39, 0x39,
-  0x28, 0x3F, 0x39, 0x33, 0x58, 0x66, 0x35, 0x2E,
-  0x58, 0x24, 0x8B, 0x29, 0x20, 0x20, 0x20, 0x39,
-  0x29, 0x30, 0x55, 0xB6, 0xCC, 0x25, 0x29, 0x39,
-  0x54, 0x25, 0x22, 0x2B, 0x29, 0x2A, 0x29, 0x2B,
-  0x22, 0x24, 0x54, 0x33, 0x25, 0x22, 0x2B, 0x54,
-  0x27, 0x27, 0x62, 0x27, 0x30, 0x80, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x4D, 0x8B, 0x77, 0x36, 0x27, 0x27,
-  0x3C, 0x2F, 0x27, 0x27, 0x39, 0x39, 0x39, 0x47,
-  0x20, 0x2B, 0x2C, 0x39, 0x33, 0xB6, 0x35, 0x35,
-  0x35, 0xAF, 0x24, 0x48, 0x2A, 0x20, 0x20, 0x20,
-  0x8B, 0x2B, 0x78, 0xAF, 0x58, 0x30, 0x21, 0x28,
-  0x33, 0x25, 0x21, 0x28, 0x29, 0x29, 0x28, 0x20,
-  0x24, 0x33, 0x54, 0x33, 0x23, 0x20, 0x24, 0xD2,
-  0x27, 0x49, 0x27, 0x27, 0x56, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0xC9, 0x50, 0x56, 0x27, 0x27,
-  0x3D, 0x38, 0x3D, 0x27, 0x27, 0x47, 0x39, 0x39,
-  0x28, 0x20, 0x20, 0x2A, 0x39, 0x54, 0x43, 0x35,
-  0x35, 0x35, 0xAF, 0x23, 0x48, 0x2B, 0x20, 0x20,
-  0x2B, 0x48, 0x22, 0x60, 0x34, 0xCB, 0x25, 0x21,
-  0x33, 0x24, 0x2B, 0x29, 0x29, 0x29, 0x2B, 0x22,
-  0x25, 0x54, 0x54, 0x25, 0x22, 0x2B, 0x33, 0x27,
-  0x27, 0x32, 0x27, 0x30, 0x56, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x56, 0xC9, 0x4C, 0x36, 0x3C,
-  0x62, 0x2F, 0x2E, 0x27, 0x27, 0x54, 0x47, 0x47,
-  0x8B, 0x2B, 0x20, 0x20, 0x20, 0x3F, 0x54, 0x2E,
-  0x35, 0x35, 0x35, 0x34, 0x21, 0x8B, 0x2A, 0x20,
-  0x20, 0x2C, 0x6B, 0x25, 0x60, 0x60, 0x54, 0x23,
-  0x25, 0x22, 0x2A, 0x2C, 0x29, 0x28, 0x20, 0x24,
-  0x54, 0x63, 0x54, 0x24, 0x2B, 0x22, 0x24, 0x27,
-  0x36, 0x27, 0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0x4C, 0x36,
-  0x66, 0xD3, 0x27, 0x2F, 0x27, 0x54, 0x54, 0x27,
-  0x26, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x6B, 0x63,
-  0x35, 0x35, 0x35, 0x62, 0xCB, 0x2A, 0x3F, 0x28,
-  0x2B, 0x2A, 0x50, 0x29, 0x33, 0x30, 0x54, 0x25,
-  0x24, 0x20, 0x29, 0x2C, 0x2C, 0x2A, 0x21, 0x33,
-  0xC4, 0xC4, 0x33, 0x21, 0x29, 0x22, 0x27, 0x27,
-  0x99, 0x27, 0x31, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0x3D,
-  0x3D, 0x3C, 0x3C, 0x55, 0x54, 0x54, 0x54, 0x20,
-  0x27, 0x2C, 0x39, 0x20, 0x20, 0x20, 0x20, 0x48,
-  0x30, 0x62, 0x35, 0x35, 0x42, 0x54, 0x39, 0x39,
-  0x2C, 0x28, 0x3F, 0x8B, 0x20, 0x33, 0x54, 0x24,
-  0x22, 0x2B, 0x2C, 0x2C, 0x2C, 0x2B, 0x24, 0x54,
-  0x30, 0xC4, 0x25, 0x2B, 0x28, 0x2B, 0x27, 0x3D,
-  0x27, 0x27, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x56, 0x4F, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0x27,
-  0x20, 0x20, 0x20, 0x54, 0x54, 0x54, 0x54, 0x20,
-  0x20, 0x2D, 0x2D, 0x29, 0x20, 0x20, 0x20, 0x20,
-  0x48, 0x60, 0x66, 0x35, 0x62, 0x34, 0x22, 0x2C,
-  0x2C, 0x3F, 0x6B, 0x48, 0x2C, 0x22, 0x23, 0x23,
-  0x20, 0x2A, 0x2C, 0x29, 0x29, 0x20, 0x25, 0xC4,
-  0x30, 0x54, 0x22, 0x29, 0x28, 0xD2, 0x27, 0x35,
-  0x27, 0x49, 0x56, 0xB9, 0xB9, 0xB9, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x4F, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0x40, 0x20,
-  0x20, 0x54, 0x54, 0x54, 0x20, 0x20, 0x20, 0x20,
-  0x2D, 0x2D, 0x2D, 0x49, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x6B, 0x6C, 0x42, 0x2E, 0xB6, 0x54, 0x28,
-  0x29, 0x2C, 0x6B, 0x48, 0x3F, 0x2A, 0x20, 0x22,
-  0x2B, 0x28, 0x2C, 0x28, 0x29, 0x20, 0x33, 0x30,
-  0x30, 0x54, 0x20, 0x2C, 0x29, 0x27, 0x27, 0x3D,
-  0x27, 0x40, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x4D, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x56, 0x63, 0x56, 0x54, 0x54,
-  0x54, 0x54, 0x20, 0xD3, 0x45, 0x51, 0x51, 0x49,
-  0x7C, 0x2D, 0x2D, 0x49, 0x49, 0x20, 0x20, 0x20,
-  0x20, 0x2A, 0x2A, 0xCC, 0xB6, 0x8A, 0x60, 0x22,
-  0x28, 0x29, 0x3F, 0x6B, 0x39, 0x29, 0x2B, 0x20,
-  0x28, 0x2C, 0x28, 0x2A, 0x2A, 0x24, 0xC4, 0x30,
-  0xC4, 0x33, 0x2B, 0x39, 0xCD, 0x27, 0x3C, 0x27,
-  0x27, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x4D, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x63, 0x63, 0x49, 0x2D, 0x20,
-  0x20, 0x2D, 0xD3, 0x49, 0x66, 0x2D, 0x49, 0x49,
-  0x49, 0x49, 0x49, 0x49, 0x49, 0x8B, 0x2B, 0x20,
-  0x20, 0x20, 0x39, 0x23, 0x6C, 0xAF, 0xCB, 0x23,
-  0x28, 0x28, 0x29, 0x2A, 0x2A, 0x2A, 0x2A, 0x20,
-  0x29, 0x39, 0x2B, 0x2B, 0x2B, 0x25, 0x78, 0xC4,
-  0x63, 0x23, 0x29, 0x39, 0x27, 0x27, 0x3D, 0x27,
-  0x27, 0x56, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x80, 0x4F, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x2D, 0x49, 0x2D, 0x49,
-  0x49, 0x2D, 0x49, 0x2D, 0x49, 0x2D, 0x2D, 0x2D,
-  0x49, 0x49, 0x35, 0x49, 0x2D, 0x2D, 0x39, 0x28,
-  0x20, 0x20, 0x2A, 0x28, 0x33, 0x60, 0xC4, 0x22,
-  0x2C, 0x2A, 0x2A, 0x22, 0x23, 0x22, 0x20, 0x21,
-  0x2C, 0x29, 0x20, 0x2B, 0x2B, 0x54, 0x30, 0xC4,
-  0x63, 0x22, 0x2C, 0x27, 0x27, 0x27, 0x3D, 0x27,
-  0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x2D, 0x49, 0x2D, 0x49,
-  0x61, 0x49, 0x2D, 0x49, 0x49, 0x2D, 0x2D, 0x49,
-  0x49, 0x49, 0x2F, 0x49, 0x2D, 0x78, 0x29, 0x28,
-  0x2C, 0x2A, 0x2B, 0x39, 0x2B, 0x25, 0x33, 0x20,
-  0x2C, 0x20, 0x2A, 0x24, 0x54, 0x54, 0x23, 0x23,
-  0x2C, 0x2A, 0x22, 0x2B, 0x20, 0x63, 0x30, 0x63,
-  0xC4, 0x21, 0x39, 0x27, 0x27, 0x27, 0x35, 0x36,
-  0x27, 0x56, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x2D, 0x49, 0x49, 0x49,
-  0x49, 0x27, 0x27, 0x2D, 0x38, 0x27, 0x36, 0x36,
-  0x49, 0x27, 0x49, 0x2D, 0x2D, 0x44, 0x24, 0x2B,
-  0x20, 0x2C, 0x3F, 0x6B, 0x2A, 0x20, 0x21, 0x28,
-  0x2C, 0x20, 0x2B, 0x24, 0x30, 0xCB, 0x63, 0x54,
-  0x28, 0x20, 0x24, 0x2B, 0x23, 0x78, 0xC4, 0x63,
-  0x63, 0x2B, 0x3F, 0x27, 0x27, 0x27, 0x38, 0x33,
-  0x3D, 0xB9, 0x56, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x63, 0x49, 0x49, 0x49,
-  0x49, 0x49, 0x3D, 0x3D, 0x27, 0x27, 0x27, 0x2D,
-  0x49, 0x49, 0x49, 0x2D, 0x62, 0x5F, 0xC4, 0x20,
-  0x22, 0x2A, 0x6B, 0x8B, 0x2C, 0x2B, 0x2A, 0x3F,
-  0x3F, 0x2A, 0x21, 0x21, 0xCB, 0x58, 0x6C, 0x60,
-  0x20, 0x23, 0x24, 0x2A, 0x25, 0x78, 0x63, 0x63,
-  0x54, 0x2A, 0x28, 0x27, 0x27, 0x27, 0x27, 0x62,
-  0x3C, 0xB9, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x49, 0x2D, 0x2D,
-  0x2D, 0x3D, 0x2F, 0x3C, 0x2D, 0x3C, 0x27, 0x38,
-  0x2D, 0x49, 0x2D, 0x2D, 0xD1, 0x43, 0x30, 0x20,
-  0x24, 0x21, 0x21, 0x21, 0x2B, 0x2A, 0x29, 0x8B,
-  0x6B, 0x29, 0x2B, 0x2A, 0x30, 0x55, 0x55, 0x34,
-  0x22, 0x23, 0x24, 0x29, 0x54, 0x30, 0x63, 0x63,
-  0x25, 0x29, 0x22, 0x3C, 0xA5, 0xD4, 0xD5, 0x27,
-  0x31, 0x56, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x2D, 0x2E,
-  0x3E, 0x27, 0x27, 0x27, 0x27, 0x27, 0x36, 0x44,
-  0x3C, 0x27, 0x2D, 0xC4, 0x78, 0xCC, 0x54, 0x2B,
-  0x25, 0x24, 0x63, 0x60, 0x63, 0x24, 0x2A, 0x6B,
-  0x3F, 0x39, 0x28, 0x21, 0x33, 0xB6, 0x44, 0x58,
-  0x22, 0x23, 0x24, 0x2A, 0x30, 0x30, 0x63, 0x63,
-  0x24, 0x39, 0x22, 0xBB, 0x9C, 0xB2, 0x9D, 0xA8,
-  0x27, 0x8B, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0xB9,
-  0x56, 0xB9, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0x56, 0xD6, 0xD6, 0xD7,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x32,
-  0x3D, 0x27, 0x39, 0x33, 0xC4, 0xC4, 0x22, 0x28,
-  0x25, 0x54, 0x30, 0xD1, 0xD1, 0x60, 0x23, 0x6B,
-  0x3F, 0x39, 0x2C, 0x2B, 0x20, 0x58, 0x8A, 0x58,
-  0x22, 0x23, 0x23, 0x2B, 0x78, 0x30, 0xC4, 0xC4,
-  0x23, 0x29, 0xBB, 0xBB, 0xD8, 0xB2, 0x9D, 0xA9,
-  0xA9, 0x3C, 0x60, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
-  0x56, 0xB9, 0x56, 0x80, 0xB9, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0xB9, 0x56, 0xD9, 0x85, 0x85, 0x85,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x2D,
-  0xA0, 0x83, 0x2C, 0x21, 0x30, 0x33, 0x29, 0x29,
-  0x21, 0x33, 0x54, 0x42, 0x66, 0x55, 0xC4, 0x29,
-  0x8B, 0x2C, 0x39, 0x28, 0x29, 0x31, 0x44, 0x58,
-  0x23, 0x23, 0x21, 0x20, 0x30, 0xC4, 0xC4, 0x30,
-  0x21, 0x20, 0xBB, 0xBC, 0xDA, 0xDB, 0xDC, 0xB2,
-  0x83, 0xB4, 0x3C, 0x2F, 0xB9, 0x56, 0x56, 0xB9,
-  0x56, 0xB9, 0x56, 0x80, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x56, 0xA7, 0xD4, 0x85, 0x82,
-  0x3C, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x61,
-  0x9E, 0x90, 0xDD, 0x21, 0x33, 0x25, 0x2C, 0x39,
-  0x2A, 0x24, 0x24, 0x42, 0x62, 0x43, 0x34, 0x22,
-  0x50, 0x39, 0x2C, 0x2C, 0x2A, 0x54, 0xD1, 0x58,
-  0x22, 0x22, 0x2B, 0x22, 0x30, 0xC4, 0x30, 0x60,
-  0x20, 0xDE, 0xBB, 0xD9, 0x84, 0x84, 0xDF, 0xA9,
-  0xDB, 0xDB, 0x61, 0x27, 0x38, 0x4D, 0x56, 0x56,
-  0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x56, 0x56, 0x8D, 0xD9, 0xD5, 0xA6,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0xBB,
-  0x85, 0xDB, 0xDD, 0x21, 0x22, 0x22, 0x3F, 0x39,
-  0x2C, 0x2B, 0x25, 0x34, 0x62, 0x66, 0xD1, 0xC4,
-  0x6B, 0x39, 0x2C, 0x39, 0x29, 0x21, 0x58, 0xCC,
-  0x22, 0x21, 0x29, 0x23, 0x30, 0x30, 0x30, 0x5E,
-  0x82, 0xBB, 0xE0, 0xB1, 0xE1, 0x9C, 0xD4, 0xDC,
-  0x9D, 0xA9, 0xE2, 0x27, 0x27, 0x27, 0x4D, 0x56,
-  0x56, 0xB9, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x4C, 0x48, 0xA8, 0xA8, 0xE3, 0x8C,
-  0xC6, 0x3C, 0x27, 0x27, 0x27, 0xE4, 0xA6, 0xE5,
-  0x83, 0xA9, 0xE6, 0xAF, 0x54, 0x2B, 0x8B, 0x39,
-  0x39, 0x29, 0x20, 0x54, 0x42, 0x42, 0xB6, 0xCC,
-  0x2A, 0x29, 0x39, 0x39, 0x2C, 0x2C, 0xCC, 0xCC,
-  0x22, 0x20, 0x39, 0xE7, 0xC0, 0xD9, 0xA7, 0xBC,
-  0x8D, 0xAA, 0x9C, 0xE8, 0x9C, 0x9D, 0xD4, 0xD4,
-  0xD8, 0xA9, 0x84, 0xC7, 0x27, 0x27, 0x27, 0x2A,
-  0x56, 0x56, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0x56, 0x56, 0x48, 0x50, 0xAA, 0xE3, 0xE3, 0xC0,
-  0xA6, 0x9A, 0xBA, 0xC8, 0x9A, 0xDE, 0x9B, 0xD5,
-  0xE8, 0xD8, 0xD5, 0x2E, 0x58, 0x33, 0x6B, 0x39,
-  0x2C, 0x39, 0x29, 0x28, 0xD1, 0x43, 0xB6, 0xAF,
-  0x23, 0x28, 0x2C, 0x39, 0x39, 0x8B, 0x30, 0x31,
-  0x21, 0x20, 0x3F, 0xBB, 0xDF, 0xDF, 0xD5, 0xA8,
-  0xD5, 0x9C, 0x8E, 0xB2, 0x9D, 0xE9, 0xD4, 0xD8,
-  0x90, 0xB2, 0xA9, 0x8F, 0x27, 0x27, 0x27, 0x27,
-  0x2F, 0x56, 0x56, 0xB9, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0x56, 0xB9, 0x48, 0x48, 0x75, 0xE3, 0xAA, 0xAA,
-  0xC0, 0xB4, 0xB4, 0xB4, 0x75, 0x9B, 0xD9, 0x83,
-  0x9D, 0x90, 0xDF, 0xDD, 0x8A, 0x31, 0x4B, 0x2C,
-  0x2C, 0x29, 0x2C, 0x3F, 0x6C, 0x55, 0xD1, 0x55,
-  0x54, 0x29, 0x28, 0x39, 0x39, 0x6B, 0x24, 0x60,
-  0x20, 0x2B, 0x3F, 0xA7, 0xB1, 0x9D, 0xA9, 0x8E,
-  0xE5, 0xE5, 0xDF, 0xE0, 0xA9, 0x9D, 0xDF, 0xDF,
-  0xEA, 0x9D, 0xB2, 0x84, 0xAA, 0x27, 0x27, 0x27,
-  0x27, 0x35, 0x56, 0x56, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0xB9, 0x48, 0x48, 0xA6, 0x9B, 0xE3, 0xAA,
-  0xAA, 0x9B, 0x9B, 0x9B, 0xAA, 0xE3, 0xD5, 0xD4,
-  0x9D, 0xA9, 0xA9, 0x9D, 0xEB, 0xAF, 0x23, 0x28,
-  0x2C, 0x29, 0x28, 0x39, 0x54, 0xCC, 0xAF, 0x55,
-  0x30, 0x29, 0x2B, 0x2C, 0x39, 0x39, 0x2B, 0xC4,
-  0x2B, 0x29, 0x39, 0xA7, 0x8E, 0x9D, 0x83, 0xE5,
-  0xB1, 0xDB, 0xDC, 0xE0, 0xDC, 0x84, 0xE9, 0x84,
-  0x83, 0xD4, 0xEC, 0x83, 0x8F, 0xE4, 0x27, 0x27,
-  0x27, 0x27, 0x56, 0x56, 0x56, 0x56, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0xB9, 0x56, 0x40, 0x50, 0x9A, 0x75, 0xE3, 0xE3,
-  0xE3, 0xD9, 0x8D, 0xAA, 0xD9, 0xA8, 0xB2, 0xDC,
-  0xB2, 0x8D, 0x84, 0xEA, 0xB1, 0xEB, 0x54, 0x29,
-  0x28, 0x2C, 0x2A, 0x28, 0x2B, 0x78, 0xCC, 0x58,
-  0xCB, 0x20, 0x20, 0x29, 0x39, 0x39, 0x2C, 0x25,
-  0x29, 0x2C, 0x39, 0xBB, 0xD9, 0xD9, 0x9D, 0x9D,
-  0xB2, 0xB1, 0xD4, 0xDB, 0xB1, 0x9D, 0xD4, 0xEA,
-  0xB1, 0x8D, 0xD8, 0x8E, 0x8F, 0xAA, 0x27, 0x27,
-  0x27, 0x3D, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0x56,
-  0x56, 0x56, 0x47, 0xE4, 0xA6, 0x75, 0xAA, 0xA8,
-  0x9C, 0x9C, 0xE1, 0x9C, 0x9C, 0x8E, 0xD8, 0x9D,
-  0xA9, 0xDB, 0xA9, 0xDC, 0xD8, 0xDA, 0xD4, 0x2B,
-  0x20, 0x2C, 0x28, 0x2A, 0x28, 0x63, 0x31, 0x58,
-  0xCB, 0x24, 0x20, 0x2B, 0x2C, 0x39, 0x6B, 0x21,
-  0x39, 0x6B, 0x2C, 0xC0, 0xE0, 0xB1, 0xB2, 0x9D,
-  0x8E, 0xD8, 0xE0, 0xD9, 0x84, 0xDB, 0xD8, 0xB1,
-  0x8E, 0xB2, 0xE2, 0x9C, 0x83, 0x9E, 0xBC, 0x3D,
-  0xD3, 0x56, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0xB9, 0xB9,
-  0x56, 0x4F, 0x27, 0x61, 0xA6, 0x9B, 0xE3, 0xA9,
-  0xE9, 0xD4, 0xDA, 0xDB, 0x8E, 0xE1, 0xE9, 0x8E,
-  0xD4, 0xA8, 0xE0, 0x84, 0xE8, 0xB1, 0xDC, 0x9D,
-  0x20, 0x29, 0x29, 0x2B, 0x2C, 0x54, 0x78, 0xCC,
-  0x78, 0x33, 0x2A, 0x20, 0x29, 0x39, 0x50, 0x2A,
-  0x6B, 0x8B, 0x39, 0xC0, 0x8D, 0xB1, 0xE9, 0xA9,
-  0xB2, 0xDC, 0x8E, 0xDC, 0xE1, 0xDA, 0xA9, 0x8E,
-  0xEA, 0xE2, 0x83, 0xE8, 0x8E, 0x83, 0xE2, 0xED,
-  0xB9, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x56, 0xB9,
-  0xC9, 0x27, 0x27, 0xE4, 0xA6, 0x9B, 0xD5, 0xA8,
-  0xD4, 0xB2, 0xD8, 0xDA, 0xD9, 0xE8, 0xE9, 0xE8,
-  0xD8, 0xB1, 0xDA, 0xB2, 0xE9, 0x8E, 0xEC, 0xDA,
-  0x22, 0x20, 0x39, 0x2B, 0x39, 0x24, 0xC4, 0x30,
-  0x30, 0x54, 0x22, 0x29, 0x29, 0x39, 0x48, 0x2C,
-  0x39, 0x6B, 0x39, 0xC0, 0x8D, 0xB1, 0xE9, 0xB2,
-  0xB2, 0x8E, 0xA9, 0xD8, 0xDA, 0xB1, 0xA9, 0xDA,
-  0x9C, 0xDC, 0x8E, 0xD4, 0xE8, 0xE8, 0x8F, 0x9B,
-  0x4F, 0xB9, 0x56, 0xB9, 0x56, 0xB9, 0xB9, 0xB9,
-  0xB9, 0xB9, 0xB9, 0xB9, 0x56, 0x56, 0x4F, 0x6B,
-  0x27, 0x27, 0x27, 0xD7, 0xDE, 0xAA, 0xE3, 0xA8,
-  0xB2, 0xD5, 0xE5, 0x90, 0xE2, 0xA9, 0xE9, 0xB2,
-  0xDA, 0xB2, 0xE1, 0xB2, 0xE9, 0x8E, 0xDA, 0xDF,
-  0x78, 0x2A, 0x2C, 0x2A, 0x6B, 0x28, 0x23, 0x54,
-  0x63, 0xC4, 0x33, 0x28, 0x2C, 0x39, 0x47, 0x39,
-  0x28, 0x2C, 0x29, 0xBB, 0x8D, 0x83, 0xE9, 0xD4,
-  0xB2, 0xE9, 0xE9, 0xE8, 0xD4, 0xD8, 0xD4, 0xA9,
-  0xDA, 0xB2, 0xE9, 0xA8, 0xB2, 0xA8, 0xD5, 0xAA,
-  0xC6, 0x56, 0x56, 0x56, 0x56, 0x56, 0xB9, 0x56,
-  0x56, 0x56, 0x56, 0x56, 0x56, 0xC9, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xB8, 0xB4, 0x9B, 0xE3, 0x8E,
-  0x9D, 0x8E, 0xB2, 0xE8, 0xE8, 0x8E, 0xB2, 0xDA,
-  0xB2, 0x8E, 0xEC, 0xB2, 0x8E, 0xB2, 0xBB, 0x58,
-  0xAF, 0x33, 0x50, 0x39, 0x6B, 0x39, 0x29, 0x20,
-  0x33, 0x30, 0x78, 0x23, 0x6B, 0x6B, 0x48, 0x6B,
-  0x2B, 0x2A, 0x29, 0xBB, 0xE5, 0x9C, 0xB1, 0xB2,
-  0xE5, 0x84, 0x8E, 0x9C, 0x84, 0xB2, 0xB2, 0x9D,
-  0x84, 0xDF, 0xA9, 0x84, 0x8E, 0xA8, 0xE3, 0x9B,
-  0xA6, 0xD7, 0x80, 0x4F, 0x56, 0x56, 0x56, 0x4F,
-  0x4F, 0x4F, 0x4F, 0x2A, 0x2D, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xB8, 0xB4, 0xAA, 0xD5, 0xA9,
-  0x9D, 0xB2, 0x90, 0xEA, 0xE9, 0xE2, 0xE1, 0x8E,
-  0xB2, 0x9D, 0x8E, 0xB1, 0xA7, 0xEE, 0x63, 0xD1,
-  0x2E, 0xCC, 0x28, 0x48, 0x8B, 0x47, 0x6B, 0x28,
-  0x23, 0x78, 0x6C, 0x54, 0x29, 0x50, 0x50, 0x6B,
-  0x23, 0x20, 0xBB, 0xBC, 0xBB, 0x8D, 0xE3, 0xDF,
-  0x9C, 0xA9, 0x8D, 0xA8, 0xD9, 0x90, 0x9D, 0xA9,
-  0xDC, 0xA9, 0x83, 0xB2, 0xA9, 0xD4, 0xE3, 0x9B,
-  0x8C, 0xEF, 0x27, 0x27, 0x27, 0x3C, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xF0, 0xB4, 0x9B, 0xE3, 0x84,
-  0x9D, 0x84, 0x90, 0xB1, 0xA9, 0x9C, 0xD9, 0xB1,
-  0xB2, 0xEA, 0xBB, 0x51, 0x24, 0x30, 0x30, 0x42,
-  0x66, 0x58, 0x24, 0x48, 0x50, 0x3F, 0x20, 0x25,
-  0x22, 0x60, 0x34, 0x30, 0x20, 0x8B, 0x8B, 0x39,
-  0x54, 0x24, 0x2B, 0xC0, 0xC0, 0xC0, 0xBB, 0x9B,
-  0xBC, 0xAA, 0xAA, 0xE3, 0xE3, 0x9C, 0xB2, 0xD4,
-  0x83, 0xD8, 0xE8, 0x83, 0x84, 0xE8, 0xE5, 0x75,
-  0x9A, 0xF0, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xF0, 0xB4, 0x9B, 0xE3, 0xA8,
-  0xA9, 0xD8, 0x8E, 0xEA, 0xA8, 0x9C, 0xD9, 0xE0,
-  0xC0, 0x5E, 0x2C, 0x20, 0x54, 0x60, 0x30, 0x66,
-  0xB6, 0xCC, 0x63, 0x3F, 0x8B, 0x28, 0x22, 0x33,
-  0x23, 0x31, 0xAF, 0x31, 0x22, 0x6B, 0x6B, 0x29,
-  0x30, 0x54, 0x22, 0x89, 0xBA, 0xED, 0xA6, 0x8C,
-  0xB4, 0xC0, 0xB4, 0x75, 0x75, 0x9B, 0x9B, 0xE5,
-  0xA9, 0xD5, 0x8E, 0x8E, 0x9C, 0xE3, 0x75, 0x8C,
-  0xC8, 0xF1, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xF1, 0x9A, 0xB4, 0x9B, 0xE3,
-  0xE3, 0xA8, 0xE3, 0xE5, 0xAA, 0xBC, 0xC0, 0x9A,
-  0x26, 0x29, 0x20, 0x24, 0x63, 0x60, 0x54, 0x43,
-  0x34, 0xCB, 0x30, 0x39, 0x2C, 0x20, 0x24, 0x54,
-  0x22, 0x34, 0x34, 0x31, 0x24, 0x3F, 0x2C, 0x2B,
-  0x31, 0x30, 0x25, 0x2A, 0x6B, 0x29, 0x20, 0xF2,
-  0xBA, 0xBF, 0xC8, 0x9A, 0xA6, 0xA6, 0x8C, 0xB4,
-  0x9B, 0xAA, 0xAA, 0xAA, 0x9B, 0x75, 0xDE, 0xBF,
-  0x81, 0xEF, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
-  0x27, 0x27, 0x27, 0xEF, 0xBA, 0x9A, 0xB4, 0x75,
-  0x9B, 0x9B, 0x9B, 0xC0, 0xB4, 0x9A, 0xA5, 0xC4,
-  0x30, 0x28, 0x22, 0x33, 0x30, 0x30, 0x23, 0x34,
-  0x31, 0x30, 0xC4, 0x2C, 0x2B, 0x22, 0x33, 0x63,
-  0x21, 0x58, 0x6C, 0x60, 0x25, 0x39, 0x28, 0x2B,
-  0xCC, 0x6C, 0x63, 0x20, 0x6B, 0x28, 0x2B, 0x20,
-  0x63, 0x43, 0xF3, 0xEF, 0xF0, 0x81, 0xBA, 0xF4,
-  0xF4, 0xA6, 0xDE, 0x8C, 0xA6, 0x9A, 0xBA, 0x81,
-  0xB0, 0xE4, 0xA1, 0x20, 0x20, 0x23, 0x31, 0xC4,
-  0x30, 0x24, 0x33, 0x31, 0x31, 0x60, 0x43, 0x35,
-  0x35, 0x55, 0x6C, 0xEF, 0x81, 0xC8, 0x9A, 0xA6,
-  0xB4, 0xB4, 0x8C, 0xA6, 0xBA, 0x68, 0x30, 0x30,
-  0x30, 0x2B, 0x25, 0x54, 0xC4, 0x54, 0x24, 0x78,
-  0x63, 0x63, 0x30, 0x29, 0x21, 0x24, 0x54, 0x63,
-  0x23, 0x34, 0xCB, 0x30, 0x25, 0x39, 0x20, 0x20,
-  0x58, 0x34, 0x60, 0x23, 0x6B, 0x29, 0x28, 0x20,
-  0x22, 0xB6, 0x42, 0xB6, 0x58, 0x54, 0xF5, 0xD7,
-  0xA5, 0xBA, 0xBA, 0xBA, 0xBA, 0x81, 0xA5, 0xF1,
-  0xE4, 0x2A, 0x39, 0x20, 0x20, 0x20, 0x31, 0x60,
-  0x54, 0x28, 0x2B, 0x22, 0x33, 0x30, 0x43, 0x35,
-  0x66, 0xD1, 0x34, 0xE4, 0xEF, 0x81, 0xC8, 0x9A,
-  0x9A, 0xC8, 0xC8, 0x81, 0xF6, 0x31, 0x63, 0x31,
-  0x78, 0x2B, 0x54, 0x63, 0x54, 0x24, 0x23, 0x54,
-  0x63, 0x54, 0x63, 0x2C, 0x23, 0x33, 0x63, 0x54,
-  0x25, 0x31, 0x78, 0x30, 0x25, 0x3F, 0x20, 0x20,
-  0xAF, 0x58, 0xCC, 0x33, 0x39, 0x29, 0x29, 0x2A,
-  0x29, 0x58, 0x43, 0x42, 0xD1, 0xCB, 0x2C, 0x2C,
-  0x37, 0xCD, 0xEF, 0xB0, 0xF0, 0xB0, 0xEF, 0xE4,
-  0x63, 0x20, 0x20, 0x2C, 0x2C, 0x21, 0xCB, 0x78,
-  0x54, 0x39, 0x39, 0x28, 0x2B, 0x28, 0x2B, 0xCB,
-  0x55, 0xB6, 0xD1, 0x28, 0xE4, 0xD7, 0xB8, 0xF0,
-  0xA5, 0xB0, 0xEF, 0x26, 0x23, 0x54, 0x31, 0x58,
-  0xCB, 0x20, 0x63, 0x63, 0x25, 0x2B, 0x54, 0x78,
-  0x30, 0x63, 0x54, 0x28, 0x33, 0x63, 0x63, 0x33,
-  0x54, 0x78, 0xC4, 0x30, 0x24, 0x2C, 0x22, 0x22,
-  0x55, 0x55, 0x34, 0x30, 0x28, 0x2C, 0x29, 0x29,
-  0x28, 0x30, 0xB6, 0x42, 0x43, 0x55, 0x22, 0x29,
-  0x2C, 0x2B, 0x2B, 0x3F, 0xE4, 0xE4, 0x43, 0x66,
-  0x30, 0x23, 0x24, 0x2A, 0x28, 0x2B, 0x54, 0x63,
-  0x33, 0x39, 0x28, 0x20, 0x20, 0x20, 0x2B, 0x31,
-  0x30, 0xD1, 0x43, 0x30, 0x39, 0x28, 0xE4, 0xE4,
-  0xD7, 0xF5, 0x2B, 0x6B, 0x20, 0x30, 0x34, 0xD1,
-  0x60, 0x23, 0x63, 0x54, 0x22, 0x47, 0x60, 0xCB,
-  0xC4, 0xC4, 0x25, 0x22, 0x54, 0xC4, 0x63, 0x23,
-  0xC4, 0xC4, 0x63, 0xC4, 0x23, 0x2A, 0x24, 0x22,
-  0x55, 0x55, 0xAF, 0x6C, 0x22, 0x39, 0x2C, 0x39,
-  0x28, 0x23, 0xD1, 0x43, 0x42, 0x8A, 0x63, 0x39,
-  0x39, 0x2A, 0x20, 0x6B, 0x33, 0xCC, 0xD1, 0xB6,
-  0x30, 0x24, 0x54, 0x63, 0x31, 0xCC, 0xCC, 0xCB,
-  0xC4, 0x2A, 0x39, 0x20, 0x20, 0x20, 0x39, 0x30,
-  0x30, 0x6C, 0x43, 0x43, 0x6C, 0x63, 0x25, 0x24,
-  0x63, 0x63, 0x63, 0x25, 0x63, 0xCC, 0xD1, 0x34,
-  0x63, 0x25, 0x54, 0x25, 0x2A, 0x28, 0x31, 0xCB,
-  0x63, 0x78, 0x24, 0x33, 0xC4, 0xC4, 0x33, 0x2C,
-  0xC4, 0x54, 0x54, 0x30, 0x21, 0x22, 0x25, 0x23,
-  0x55, 0x55, 0xD1, 0x58, 0x33, 0x6B, 0x2C, 0x39,
-  0x39, 0x39, 0x34, 0x43, 0x42, 0x43, 0xCC, 0x2B,
-  0x28, 0x29, 0x20, 0x28, 0x21, 0x30, 0xCC, 0xAF,
-  0x54, 0x23, 0xC4, 0x54, 0x58, 0x2E, 0x35, 0x42,
-  0x55, 0x54, 0x8B, 0x2A, 0x20, 0x20, 0x28, 0x22,
-  0x78, 0x30, 0xD1, 0x43, 0x44, 0x6C, 0xC4, 0xC4,
-  0x60, 0x31, 0x31, 0x63, 0x6C, 0xAF, 0xCC, 0xCB,
-  0x24, 0x25, 0x33, 0x23, 0x2C, 0x24, 0x31, 0x30,
-  0x63, 0xC4, 0x21, 0x54, 0x30, 0x63, 0x24, 0x2A,
-  0x54, 0x63, 0x54, 0xC4, 0x2B, 0x24, 0x33, 0x24,
-  0x34, 0x55, 0xD1, 0x55, 0x30, 0x28, 0x29, 0x39,
-  0x39, 0x8B, 0x63, 0x55, 0x42, 0x66, 0xB6, 0x25,
-  0x29, 0x29, 0x29, 0x28, 0x2A, 0x54, 0x78, 0x6C,
-  0x23, 0x20, 0x25, 0x30, 0xCB, 0x62, 0x35, 0x35,
-  0x35, 0x44, 0x24, 0x6B, 0x29, 0x20, 0x2A, 0x39,
-  0x28, 0x63, 0x34, 0xB6, 0x34, 0xCB, 0x63, 0x30,
-  0x31, 0x31, 0x30, 0x30, 0xCC, 0x60, 0x63, 0xC4,
-  0x20, 0x33, 0x25, 0x20, 0x48, 0x33, 0x30, 0x54,
-  0x78, 0x54, 0x2B, 0x63, 0x30, 0x63, 0x23, 0x22,
-  0x63, 0x63, 0x63, 0x33, 0x28, 0x25, 0x54, 0x24,
-  0x78, 0xAF, 0xD1, 0xD1, 0xCC, 0x22, 0x39, 0x39,
-  0x2C, 0x3F, 0x2B, 0x34, 0xB6, 0x43, 0x43, 0xC4,
-  0x2B, 0x28, 0x39, 0x50, 0x2C, 0x24, 0x63, 0x78,
-  0x21, 0x2C, 0x2A, 0x23, 0x54, 0xD1, 0x35, 0x35,
-  0x35, 0x35, 0x55, 0x22, 0x39, 0x2C, 0x2C, 0x2C,
-  0x20, 0x30, 0xCC, 0x6C, 0xCB, 0x30, 0x54, 0x30,
-  0x78, 0x63, 0x78, 0x30, 0x54, 0x78, 0x30, 0x23,
-  0x2B, 0x33, 0x24, 0x28, 0x39, 0x24, 0x54, 0x30,
-  0x78, 0x33, 0x25, 0xC4, 0xC4, 0x33, 0x39, 0x25,
-  0xC4, 0x63, 0xC4, 0x24, 0x20, 0x54, 0x54, 0x25,
-  0x63, 0xCC, 0xD1, 0xB6, 0x55, 0x54, 0x39, 0x29,
-  0x39, 0x2C, 0x6B, 0x30, 0xAF, 0xB6, 0xB6, 0x60,
-  0x22, 0x2A, 0x2C, 0x39, 0x2C, 0x21, 0x54, 0x63,
-  0x21, 0x50, 0x2C, 0x2C, 0x2B, 0x25, 0x62, 0x35,
-  0x35, 0x35, 0x35, 0xCC, 0x2B, 0x29, 0x2B, 0x20,
-  0x23, 0x25, 0xC4, 0x30, 0xC4, 0x63, 0x63, 0x63,
-  0x63, 0x33, 0x24, 0x31, 0x31, 0x31, 0x54, 0x28,
-  0x24, 0x25, 0x22, 0x6B, 0x28, 0x24, 0xC4, 0x78,
-  0x30, 0x24, 0x63, 0xC4, 0x54, 0x23, 0x29, 0x63,
-  0xC4, 0x54, 0xC4, 0x21, 0x24, 0x54, 0x54, 0x25,
-  0x30, 0xCB, 0xD1, 0xB6, 0x55, 0x63, 0x28, 0x29,
-  0x39, 0x39, 0x48, 0x33, 0x58, 0x44, 0xB6, 0x60,
-  0x24, 0x20, 0x2B, 0x28, 0x2A, 0x22, 0x54, 0x63,
-  0x21, 0x48, 0x2A, 0x2B, 0x39, 0x21, 0xB6, 0x35,
-  0x35, 0x35, 0x35, 0x42, 0x23, 0x29, 0x2A, 0x2B,
-  0x23, 0x25, 0x54, 0x54, 0x54, 0x63, 0x63, 0x30,
-  0x25, 0x2B, 0x31, 0x31, 0x31, 0x31, 0x21, 0x2C,
-  0x33, 0x25, 0x21, 0x39, 0x20, 0x25, 0x30, 0x78,
-  0xC4, 0x23, 0xC4, 0x30, 0x54, 0x20, 0x28, 0x63,
-  0x63, 0x63, 0x63, 0x20, 0x25, 0x54, 0x54, 0x20,
-};
-
-unsigned char linux_logo_bw[] __initdata = {
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
-  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
-  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
-  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
-  0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
-  0x99, 0xF9, 0xC2, 0x40, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xF3, 0xBC, 0xF9, 0x90, 0x00, 0x1F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xA0, 0x00,
-  0x8F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
-  0x83, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
-  0x19, 0xF0, 0x1F, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x03, 0xF0, 0x3F, 0xF7, 0x8F, 0xFF,
-  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0x7F, 0xF7,
-  0xC7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
-  0x6F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
-  0x01, 0xF8, 0x7F, 0xF7, 0xE7, 0xFF, 0xFF, 0xFF,
-  0xF9, 0xC0, 0x21, 0xD8, 0x7F, 0xE7, 0xEF, 0xFF,
-  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0x7B, 0xFF,
-  0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
-  0x7B, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
-  0xC0, 0x7C, 0x79, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
-  0xE3, 0x80, 0x00, 0x7C, 0x7C, 0xFF, 0xCF, 0xFF,
-  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0x77, 0xFF,
-  0xDF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
-  0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
-  0x00, 0x3F, 0xBF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF,
-  0x1E, 0x00, 0x00, 0x1F, 0x9F, 0xFF, 0x3F, 0xFF,
-  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1F, 0x9F, 0xFF,
-  0x7F, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1F,
-  0x8F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
-  0x00, 0x0F, 0xC7, 0xFC, 0xFF, 0xFF, 0xFF, 0xFC,
-  0xF8, 0x00, 0x00, 0x0F, 0xF7, 0xF9, 0xFF, 0xFF,
-  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x07, 0xFB, 0xF3,
-  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x07,
-  0xFD, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
-  0x00, 0x03, 0xFE, 0x8F, 0xFF, 0xFF, 0xFF, 0xF1,
-  0xF0, 0x00, 0x00, 0x03, 0xFE, 0x1F, 0xFF, 0xFF,
-  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xBF,
-  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
-  0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
-  0x00, 0x00, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0xC7,
-  0xC0, 0x00, 0x00, 0x01, 0xFE, 0xBF, 0xFF, 0xFF,
-  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFE, 0x9F,
-  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
-  0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
-  0x00, 0x01, 0xFE, 0x87, 0xFF, 0xFF, 0xFF, 0x9F,
-  0x80, 0x00, 0x00, 0x01, 0xFD, 0x33, 0xFF, 0xFF,
-  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0xF3,
-  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
-  0x8B, 0xF9, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
-  0x00, 0x02, 0x27, 0xF8, 0xFF, 0xFF, 0xFF, 0x99,
-  0x80, 0x00, 0x00, 0x00, 0x07, 0xF8, 0xFF, 0xFF,
-  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0x8F, 0xF8,
-  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
-  0xE3, 0xF8, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0xF8, 0x78, 0xFF, 0xFF, 0xC0, 0x40,
-  0x38, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFF,
-  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x20,
-  0x7F, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
-  0x78, 0x10, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
-  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
-  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
-  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
-  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
-  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
-  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
-  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
-  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
-  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
-  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
-  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
-  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
-  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
-  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
-  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
-  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
-  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
-  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
-
-/* Painted by Johnny Stenback <jst@uwasa.fi> */
-
-unsigned char *linux_serial_image __initdata = "\n"
-"         .u$e.\n"
-"       .$$$$$:S\n"
-"       $\"*$/\"*$$\n"
-"       $.`$ . ^F\n"
-"       4k+#+T.$F\n"
-"       4P+++\"$\"$\n"
-"       :R\"+  t$$B\n"
-"    ___#       $$$\n"
-"    |  |       R$$k\n"
-"   dd. | Linux  $!$\n"
-"   ddd |  Sparc $9$F\n"
-" '!!!!!$       !!#!`\n"
-"  !!!!!*     .!!!!!`\n"
-"'!!!!!!!W..e$$!!!!!!`    %s\n"
-" \"~^^~         ^~~^\n"
-"\n";
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.1.36/linux/include/asm-sparc64/processor.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/processor.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.21 1997/04/14 17:05:18 jj Exp $
+/* $Id: processor.h,v 1.23 1997/04/26 22:52:34 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -71,7 +71,7 @@
 #define SPARC_FLAG_32BIT        0x8    /* task is older 32-bit binary */
 
 #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
-		    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC }
+		    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  {							\
 /* FPU regs */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	\
diff -u --recursive --new-file v2.1.36/linux/include/asm-sparc64/termbits.h linux/include/asm-sparc64/termbits.h
--- v2.1.36/linux/include/asm-sparc64/termbits.h	Mon Apr 14 16:28:24 1997
+++ linux/include/asm-sparc64/termbits.h	Mon May 12 10:35:43 1997
@@ -148,7 +148,13 @@
 #define HUPCL	  0x00000400
 #define CLOCAL	  0x00000800
 #define CBAUDEX   0x00001000
+/* We'll never see these speeds with the Zilogs, but for completeness... */
 #define  B57600   0x00001001
+#define  B115200  0x00001002
+#define  B230400  0x00001003
+#define  B460800  0x00001004
+/* This is what we can do with the Zilogs. */
+#define  B76800   0x00001005
 #define CIBAUD	  0x100f0000  /* input baud rate (not used) */
 #define CMSPAR    0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS	  0x80000000  /* flow control */
diff -u --recursive --new-file v2.1.36/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v2.1.36/linux/include/linux/affs_fs.h	Thu Feb  6 02:58:49 1997
+++ linux/include/linux/affs_fs.h	Mon May 12 10:35:43 1997
@@ -22,9 +22,9 @@
 
 struct DateStamp
 {
-  __u32 ds_Days;
-  __u32 ds_Minute;
-  __u32 ds_Tick;
+  u32 ds_Days;
+  u32 ds_Minute;
+  u32 ds_Tick;
 };
 
 
@@ -32,66 +32,58 @@
 
 /* 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, int *hash_pos);
-extern int		   affs_get_file_name(int bsize, void *fh_data, char **name);
-extern unsigned int	   affs_checksum_block(int bsize, void *data, int *ptype, int *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(unsigned int prot);
-extern unsigned int	   mode_to_prot(int mode);
-extern int		   affs_fix_hash_pred(struct inode *startino, int startoffset,
-		 			      int key, int newkey);
-extern int		   affs_fix_link_pred(struct inode *startino, int key, int newkey);
+extern int	affs_get_key_entry(int bsize, void *data, int entry_pos);
+extern int	affs_get_file_name(int bsize, void *fh_data, char **name);
+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(time_t secs, struct DateStamp *ds);
+extern int	prot_to_mode(unsigned int prot);
+extern u32	mode_to_prot(int mode);
+extern int	affs_fix_hash_pred(struct inode *startino, int startoffset,
+		     	      s32 key, s32 newkey);
+extern int	affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey);
+extern void	affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
+extern void	affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
 
 /* bitmap. c */
 
-extern int		   affs_count_free_blocks(struct super_block *s);
-extern int		   affs_count_free_bits(int blocksize, const char *data);
-extern void		   affs_free_block(struct super_block *sb, int block);
-extern int		   affs_new_header(struct inode *inode);
-extern int		   affs_new_data(struct inode *inode);
-extern void		   affs_make_zones(struct super_block *sb);
+extern int	affs_count_free_blocks(struct super_block *s);
+extern int	affs_count_free_bits(int blocksize, const char *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 */
 
-extern int		   affs_hash_name(const char *name, int len, int intl, int hashsize);
-extern int		   affs_lookup(struct inode *dir,const char *name, int len,
-				       struct inode **result);
-extern int		   affs_unlink(struct inode *dir, const char *name, int len);
-extern int		   affs_create(struct inode *dir, const char *name, int len, int mode,
-				       struct inode **result);
-extern int		   affs_mkdir(struct inode *dir, const char *name, int len, int mode);
-extern int		   affs_rmdir(struct inode *dir, const char *name, int len);
-extern int		   affs_link(struct inode *oldinode, struct inode *dir,
-				     const char *name, int len);
-extern int		   affs_symlink(struct inode *dir, const char *name, int len,
-				        const char *symname);
-extern int		   affs_fixup(struct buffer_head *bh, struct inode *inode);
-extern int		   affs_rename(struct inode *old_dir, const char *old_name, int old_len,
-				       struct inode *new_dir, const char *new_name, int new_len,
-				       int must_be_dir);
+extern int	affs_hash_name(const char *name, int len, int intl, int hashsize);
+extern int	affs_lookup(struct inode *dir,const char *name, int len,
+		            struct inode **result);
+extern int	affs_unlink(struct inode *dir, const char *name, int len);
+extern int	affs_create(struct inode *dir, const char *name, int len, int mode,
+		            struct inode **result);
+extern int	affs_mkdir(struct inode *dir, const char *name, int len, int mode);
+extern int	affs_rmdir(struct inode *dir, const char *name, int len);
+extern int	affs_link(struct inode *oldinode, struct inode *dir,
+		          const char *name, int len);
+extern int	affs_symlink(struct inode *dir, const char *name, int len,
+		             const char *symname);
+extern int	affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+			    struct inode *new_dir, const char *new_name, int new_len,
+			    int must_be_dir);
 
 /* inode.c */
 
 extern struct buffer_head *affs_bread(kdev_t dev, int block, int size);
 extern void		   affs_brelse(struct buffer_head *buf);
-extern void		   affs_put_super(struct super_block *);
-extern int		   affs_parent_ino(struct inode *dir);
-extern struct super_block *affs_read_super(struct super_block *,void *, int);
-extern void		   affs_statfs(struct super_block *, struct statfs *, int bufsiz);
-extern void		   affs_read_inode(struct inode *);
-extern void		   affs_write_inode(struct inode *);
-extern int		   affs_notify_change(struct inode *inode, struct iattr *attr);
-extern void		   affs_put_inode(struct inode *);
+extern unsigned long	   affs_parent_ino(struct inode *dir);
 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, int type);
+extern int		   affs_add_entry(struct inode *dir, struct inode *link,
+					  struct inode *inode, const char *name,
+					  int len, s32 type);
 
 /* file.c */
 
-extern int		   affs_bmap(struct inode *inode, int block);
-extern struct buffer_head *affs_getblock(struct inode *inode, int block);
 extern void		   affs_truncate(struct inode *);
 extern void		   affs_truncate_ofs(struct inode *);
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- v2.1.36/linux/include/linux/affs_fs_i.h	Fri Dec 27 02:28:30 1996
+++ linux/include/linux/affs_fs_i.h	Mon May 12 10:35:43 1997
@@ -9,19 +9,19 @@
 
 struct key_cache {
 	struct timeval	 kc_lru_time;	/* Last time this cache was used */
-	int	 kc_first;		/* First cached key */
-	int	 kc_last;		/* Last cached key */
-	int	 kc_this_key;		/* Key of extension block this data block keys are from */
+	s32	 kc_first;		/* First cached key */
+	s32	 kc_last;		/* Last cached key */
+	s32	 kc_this_key;		/* Key of extension block this data block keys are from */
 	int	 kc_this_seq;		/* Sequence number of this extension block */
-	int	 kc_next_key;		/* Key of next extension block */
-	int	 kc_keys[AFFS_KCSIZE];	/* Key cache */
+	s32	 kc_next_key;		/* Key of next extension block */
+	s32	 kc_keys[AFFS_KCSIZE];	/* Key cache */
 };
 
 #define EC_SIZE	(PAGE_SIZE - 4 * sizeof(struct key_cache) - 4) / 4
 
 struct ext_cache {
 	struct key_cache  kc[4];	/* The 4 key caches */
-	__s32	 ec[EC_SIZE];		/* Keys of assorted extension blocks */
+	s32	 ec[EC_SIZE];		/* Keys of assorted extension blocks */
 	int	 max_ext;		/* Index of last known extension block */
 };
 
@@ -29,18 +29,18 @@
  * affs fs inode data in memory
  */
 struct affs_inode_info {
-	__u32	 i_protect;		/* unused attribute bits */
-	__s32	 i_parent;		/* parent ino */
-	__s32	 i_original;		/* if != 0, this is the key of the original */
-	__s32	 i_data[AFFS_MAX_PREALLOC];	/* preallocated blocks */
-	struct ext_cache *i_ec;		/* Cache gets allocated dynamically */
-	int	 i_cache_users;		/* Cache cannot be freed while > 0 */
-	int	 i_lastblock;		/* last allocated block */
-	short	 i_pa_cnt;		/* number of preallocated blocks */
-	short	 i_pa_next;		/* Index of next block in i_data[] */
-	short	 i_pa_last;		/* Index of next free slot in i_data[] */
-	short	 i_zone;		/* write zone */
-	unsigned char i_hlink;		/* This is a fake */
+	u32	 i_protect;			/* unused attribute bits */
+	s32	 i_parent;			/* parent ino */
+	s32	 i_original;			/* if != 0, this is the key of the original */
+	s32	 i_data[AFFS_MAX_PREALLOC];	/* preallocated blocks */
+	struct ext_cache *i_ec;			/* Cache gets allocated dynamically */
+	int	 i_cache_users;			/* Cache cannot be freed while > 0 */
+	int	 i_lastblock;			/* last allocated block */
+	short	 i_pa_cnt;			/* number of preallocated blocks */
+	short	 i_pa_next;			/* Index of next block in i_data[] */
+	short	 i_pa_last;			/* Index of next free slot in i_data[] */
+	short	 i_zone;			/* write zone */
+	unsigned char i_hlink;			/* This is a fake */
 	unsigned char i_pad;
 };
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h
--- v2.1.36/linux/include/linux/affs_fs_sb.h	Wed Jul 24 23:08:28 1996
+++ linux/include/linux/affs_fs_sb.h	Mon May 12 10:35:43 1997
@@ -15,8 +15,8 @@
 
 struct affs_bm_info {
 	struct buffer_head *bm_bh;	/* Buffer head if loaded (bm_count > 0) */
-	int bm_firstblk;		/* Block number of first bit in this map */
-	int bm_key;			/* Disk block number */
+	s32 bm_firstblk;		/* Block number of first bit in this map */
+	s32 bm_key;			/* Disk block number */
 	int bm_count;			/* Usage counter */
 };
 
@@ -37,11 +37,11 @@
 
 struct affs_sb_info {
 	int s_partition_size;		/* Partition size in blocks. */
-	int s_root_block;		/* FFS root block number. */
+	s32 s_root_block;		/* FFS root block number. */
 	int s_hashsize;			/* Size of hash table. */
 	unsigned long s_flags;		/* See below. */
-	short s_uid;			/* uid to override */
-	short s_gid;			/* gid to override */
+	s16 s_uid;			/* uid to override */
+	s16 s_gid;			/* gid to override */
 	umode_t s_mode;			/* mode to override */
 	int s_reserved;			/* Number of reserved blocks. */
 	struct buffer_head *s_root_bh;	/* Cached root block. */
diff -u --recursive --new-file v2.1.36/linux/include/linux/affs_hardblocks.h linux/include/linux/affs_hardblocks.h
--- v2.1.36/linux/include/linux/affs_hardblocks.h	Sun May 19 05:22:20 1996
+++ linux/include/linux/affs_hardblocks.h	Mon May 12 10:35:43 1997
@@ -4,59 +4,59 @@
 /* Just the needed definitions for the RDB of an Amiga HD. */
 
 struct RigidDiskBlock {
-	__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;
+	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];
-	__u32	rdb_Reserved5[10];
+	u32	rdb_Reserved5[10];
 };
 
 #define	IDNAME_RIGIDDISK	0x5244534B	/* "RDSK" */
 
 struct PartitionBlock {
-	__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];
+	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 v2.1.36/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- v2.1.36/linux/include/linux/amigaffs.h	Sun May 19 05:22:20 1996
+++ linux/include/linux/amigaffs.h	Mon May 12 10:35:43 1997
@@ -56,131 +56,131 @@
 
 struct root_front
 {
-  __s32 primary_type;
-  __s32 spare1[2];
-  __s32 hash_size;
-  __s32 spare2;
-  __u32 checksum;
-  __s32 hashtable[0];
+  s32 primary_type;
+  s32 spare1[2];
+  s32 hash_size;
+  s32 spare2;
+  u32 checksum;
+  s32 hashtable[0];
 };
 
 struct root_end
 {
-  __s32 bm_flag;
-  __s32 bm_keys[25];
-  __s32 bm_extend;
+  s32 bm_flag;
+  s32 bm_keys[25];
+  s32 bm_extend;
   struct DateStamp dir_altered;
-  __u8 disk_name[40];
+  u8 disk_name[40];
   struct DateStamp disk_altered;
   struct DateStamp disk_made;
-  __s32 spare1[3];
-  __s32 secondary_type;
+  s32 spare1[3];
+  s32 secondary_type;
 };
 
 struct dir_front
 {
-  __s32 primary_type;
-  __s32 own_key;
-  __s32 spare1[3];
-  __u32 checksum;
-  __s32 hashtable[0];
+  s32 primary_type;
+  s32 own_key;
+  s32 spare1[3];
+  u32 checksum;
+  s32 hashtable[0];
 };
 
 struct dir_end
 {
-  __s32 spare1;
-  __s16 owner_uid;
-  __s16 owner_gid;
-  __u32 protect;
-  __s32 spare2;
-  __u8 comment[92];
+  s32 spare1;
+  s16 owner_uid;
+  s16 owner_gid;
+  u32 protect;
+  s32 spare2;
+  u8 comment[92];
   struct DateStamp created;
-  __u8 dir_name[32];
-  __s32 spare3[2];
-  __s32 link_chain;
-  __s32 spare4[5];
-  __s32 hash_chain;
-  __s32 parent;
-  __s32 spare5;
-  __s32 secondary_type;
+  u8 dir_name[32];
+  s32 spare3[2];
+  s32 link_chain;
+  s32 spare4[5];
+  s32 hash_chain;
+  s32 parent;
+  s32 spare5;
+  s32 secondary_type;
 };
 
 struct file_front
 {
-  __s32 primary_type;
-  __s32 own_key;
-  __s32 block_count;
-  __s32 unknown1;
-  __s32 first_data;
-  __u32 checksum;
-  __s32 blocks[0];
+  s32 primary_type;
+  s32 own_key;
+  s32 block_count;
+  s32 unknown1;
+  s32 first_data;
+  u32 checksum;
+  s32 blocks[0];
 };
 
 struct file_end
 {
-  __s32 spare1;
-  __s16 owner_uid;
-  __s16 owner_gid;
-  __u32 protect;
-  __s32 byte_size;
-  __u8 comment[92];
+  s32 spare1;
+  s16 owner_uid;
+  s16 owner_gid;
+  u32 protect;
+  s32 byte_size;
+  u8 comment[92];
   struct DateStamp created;
-  __u8 file_name[32];
-  __s32 spare2;
-  __s32 original;	/* not really in file_end */
-  __s32 link_chain;
-  __s32 spare3[5];
-  __s32 hash_chain;
-  __s32 parent;
-  __s32 extension;
-  __s32 secondary_type;
+  u8 file_name[32];
+  s32 spare2;
+  s32 original;	/* not really in file_end */
+  s32 link_chain;
+  s32 spare3[5];
+  s32 hash_chain;
+  s32 parent;
+  s32 extension;
+  s32 secondary_type;
 };
 
 struct hlink_front
 {
-  __s32 primary_type;
-  __s32 own_key;
-  __s32 spare1[3];
-  __u32 checksum;
+  s32 primary_type;
+  s32 own_key;
+  s32 spare1[3];
+  u32 checksum;
 };
 
 struct hlink_end
 {
-  __s32 spare1;
-  __s16 owner_uid;
-  __s16 owner_gid;
-  __u32 protect;
-  __u8 comment[92];
+  s32 spare1;
+  s16 owner_uid;
+  s16 owner_gid;
+  u32 protect;
+  u8 comment[92];
   struct DateStamp created;
-  __u8 link_name[32];
-  __s32 spare2;
-  __s32 original;
-  __s32 link_chain;
-  __s32 spare3[5];
-  __s32 hash_chain;
-  __s32 parent;
-  __s32 spare4;
-  __s32 secondary_type;
+  u8 link_name[32];
+  s32 spare2;
+  s32 original;
+  s32 link_chain;
+  s32 spare3[5];
+  s32 hash_chain;
+  s32 parent;
+  s32 spare4;
+  s32 secondary_type;
 };
 
 struct slink_front
 {
-  __s32 primary_type;
-  __s32 own_key;
-  __s32 spare1[3];
-  __s32 checksum;
-  __u8	symname[288];	/* depends on block size */
+  s32 primary_type;
+  s32 own_key;
+  s32 spare1[3];
+  s32 checksum;
+  u8	symname[288];	/* depends on block size */
 };
 
 struct data_front
 {
-  __s32 primary_type;
-  __s32 header_key;
-  __s32 sequence_number;
-  __s32 data_size;
-  __s32 next_data;
-  __s32 checksum;
-  __u8 data[488];	/* depends on block size */
+  s32 primary_type;
+  s32 header_key;
+  s32 sequence_number;
+  s32 data_size;
+  s32 next_data;
+  s32 checksum;
+  u8 data[488];	/* depends on block size */
 };
 
 /* Permission bits */
diff -u --recursive --new-file v2.1.36/linux/include/linux/auto_fs.h linux/include/linux/auto_fs.h
--- v2.1.36/linux/include/linux/auto_fs.h	Fri Apr  4 08:52:25 1997
+++ linux/include/linux/auto_fs.h	Tue May 13 21:59:54 1997
@@ -1,14 +1,14 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
- *
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *   
  * linux/include/linux/auto_fs.h
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *   Copyright 1997 Transmeta Corporation - All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
  * option, any later version, incorporated herein by reference.
  *
- * ------------------------------------------------------------------------- */
+ * ----------------------------------------------------------------------- */
 
 
 #ifndef _LINUX_AUTO_FS_H
@@ -20,11 +20,11 @@
 #include <linux/ioctl.h>
 #include <asm/types.h>
 
-#define AUTOFS_PROTO_VERSION 2
+#define AUTOFS_PROTO_VERSION 3
 
 enum autofs_packet_type {
-	autofs_ptype_missing,	/* Missing entry (create wait queue) */
-	/* ...need more in the future... */
+	autofs_ptype_missing,	/* Missing entry (mount request) */
+	autofs_ptype_expire,	/* Expire entry (umount request) */
 };
 
 struct autofs_packet_hdr {
@@ -39,139 +39,24 @@
 	char name[NAME_MAX+1];
 };	
 
-#define AUTOFS_IOC_READY     _IO(0x93,0x60)
-#define AUTOFS_IOC_FAIL      _IO(0x93,0x61)
-#define AUTOFS_IOC_CATATONIC _IO(0x93,0x62)
-
-#ifdef __KERNEL__
-
-#include <linux/wait.h>
-#include <linux/sched.h>
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#include <asm/segment.h>
-#define copy_to_user	memcpy_tofs
-#define copy_from_user	memcpy_fromfs
-
-#else
-
-#include <asm/uaccess.h>
-#define register_symtab(x)	do { } while (0)
-
-#endif
-
-#ifndef DPRINTK
-#ifdef DEBUG
-#define DPRINTK(D) printk D;
-#else
-#define DPRINTK(D)
-#endif
-#endif
-
-#define AUTOFS_SUPER_MAGIC 0x0187
-
-/* Structures associated with the root directory hash */
-
-#define AUTOFS_HASH_SIZE 67
-
-typedef u32 autofs_hash_t;	/* Type returned by autofs_hash() */
-
-struct autofs_dir_ent {
-	autofs_hash_t hash;
-	struct autofs_dir_ent *next;
-	struct autofs_dir_ent **back;
-	char *name;
-	int len;
-	ino_t ino;
-	time_t expiry;		/* Reserved for use in failed-lookup cache */
-};
-
-struct autofs_dirhash {
-	struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
-};
-
-struct autofs_wait_queue {
-	unsigned long wait_queue_token;
-	struct wait_queue *queue;
-	struct autofs_wait_queue *next;
-	/* We use the following to see what we are waiting for */
-	autofs_hash_t hash;
-	int len;
-	char *name;
-	/* This is for status reporting upon return */
-	int status;
-	int wait_ctr;
-};
-
-struct autofs_symlink {
+struct autofs_packet_expire {
+	struct autofs_packet_hdr hdr;
 	int len;
-	char *data;
-	time_t mtime;
+	char name[NAME_MAX+1];
 };
 
-#define AUTOFS_MAX_SYMLINKS 256
-
-#define AUTOFS_ROOT_INO      1
-#define AUTOFS_FIRST_SYMLINK 2
-#define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS)
-
-#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)
-
-#ifndef END_OF_TIME
-#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
-#endif
-
-struct autofs_sb_info {
-	struct file *pipe;
-	pid_t oz_pgrp;
-	int catatonic;
-	ino_t next_dir_ino;
-	struct autofs_wait_queue *queues; /* Wait queue pointer */
-	struct autofs_dirhash dirhash; /* Root directory hash */
-	struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS];
-	u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
-};
+#define AUTOFS_IOC_READY      _IO(0x93,0x60)
+#define AUTOFS_IOC_FAIL       _IO(0x93,0x61)
+#define AUTOFS_IOC_CATATONIC  _IO(0x93,0x62)
+#define AUTOFS_IOC_PROTOVER   _IOR(0x93,0x63,int)
+#define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long)
+#define AUTOFS_IOC_EXPIRE     _IOR(0x93,0x65,struct autofs_packet_expire)
 
-/* autofs_oz_mode(): do we see the man behind the curtain? */
-static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
-	return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
-}
+#ifdef __KERNEL__
 
 /* Init function */
 int init_autofs_fs(void);
 
-/* Hash operations */
-
-autofs_hash_t autofs_hash(const char *,int);
-void autofs_initialize_hash(struct autofs_dirhash *);
-struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int);
-void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
-void autofs_hash_delete(struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
-void autofs_hash_nuke(struct autofs_dirhash *);
-
-/* Operations structures */
-
-extern struct inode_operations autofs_root_inode_operations;
-extern struct inode_operations autofs_symlink_inode_operations;
-extern struct inode_operations autofs_dir_inode_operations;
-
-/* Initializing function */
-
-struct super_block *autofs_read_super(struct super_block *, void *,int);
-
-/* Queue management functions */
-
-int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int);
-int autofs_wait_release(struct autofs_sb_info *,unsigned long,int);
-void autofs_catatonic_mode(struct autofs_sb_info *);
-
-#ifdef DEBUG
-void autofs_say(const char *name, int len);
-#else
-#define autofs_say(n,l)
-#endif
-
 #endif /* __KERNEL__ */
+
 #endif /* _LINUX_AUTO_FS_H */
diff -u --recursive --new-file v2.1.36/linux/include/linux/console.h linux/include/linux/console.h
--- v2.1.36/linux/include/linux/console.h	Fri Apr  4 08:52:25 1997
+++ linux/include/linux/console.h	Mon May 12 10:35:43 1997
@@ -27,19 +27,20 @@
 /* DPC: 1994-04-13 !!! con_putcs is new entry !!! */
 
 struct consw {
-    unsigned long (*con_startup)(unsigned long, char **);
-    void   (*con_init)(struct vc_data *);
-    int    (*con_deinit)(struct vc_data *);
-    int    (*con_clear)(struct vc_data *, int, int, int, int);
-    int    (*con_putc)(struct vc_data *, int, int, int);
-    int    (*con_putcs)(struct vc_data *, const char *, int, int, int);
-    int    (*con_cursor)(struct vc_data *, int);
-    int    (*con_scroll)(struct vc_data *, int, int, int, int);
-    int    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
-    int    (*con_switch)(struct vc_data *);
-    int    (*con_blank)(int);
-    int    (*con_get_font)(struct vc_data *, int *, int *, char *);
-    int    (*con_set_font)(struct vc_data *, int, int, char *);
+	unsigned long (*con_startup)(unsigned long, const char **);
+	void   (*con_init)(struct vc_data *);
+	int    (*con_deinit)(struct vc_data *);
+	int    (*con_clear)(struct vc_data *, int, int, int, int);
+	int    (*con_putc)(struct vc_data *, int, int, int);
+	int    (*con_putcs)(struct vc_data *, const char *, int, int, int);
+	int    (*con_cursor)(struct vc_data *, int);
+	int    (*con_scroll)(struct vc_data *, int, int, int, int);
+	int    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
+	int    (*con_switch)(struct vc_data *);
+	int    (*con_blank)(int);
+	int    (*con_get_font)(struct vc_data *, int *, int *, char *);
+	int    (*con_set_font)(struct vc_data *, int, int, char *);
+	int    (*con_set_palette)(struct vc_data *, unsigned char *);
 };
 
 extern struct consw *conswitchp;
diff -u --recursive --new-file v2.1.36/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.1.36/linux/include/linux/cyclades.h	Sat Apr 20 11:09:56 1996
+++ linux/include/linux/cyclades.h	Mon May 12 10:35:43 1997
@@ -1,4 +1,4 @@
-/*
+/* $Revision: 1.7 $$Date: 1997/03/26 10:30:00 $
  * linux/include/linux/cyclades.h
  *
  * This file is maintained by Marcio Saito <marcio@cyclades.com> and
@@ -6,9 +6,18 @@
  *
  * This file contains the general definitions for the cyclades.c driver
  *$Log: cyclades.h,v $
- * Revision 1.5  1995/11/13  21:13:31  bentson
- * changes suggested by Michael Chastain <mec@duracef.shout.net>
- * to support use of this file in non-kernel applications
+ *Revision 1.7  1997/03/26 10:30:00  daniel
+ *new entries at the end of cyclades_port struct to reallocate
+ *variables illegally allocated within card memory.
+ *
+ *Revision 1.6  1996/09/09 18:35:30  bentson
+ *fold in changes for Cyclom-Z -- including structures for
+ *communicating with board as well modest changes to original
+ *structures to support new features.
+ *
+ *Revision 1.5  1995/11/13 21:13:31  bentson
+ *changes suggested by Michael Chastain <mec@duracef.shout.net>
+ *to support use of this file in non-kernel applications
  *
  *
  */
@@ -35,14 +44,359 @@
 #define CYGETDEFTIMEOUT         0x435908
 #define CYSETDEFTIMEOUT         0x435909
 
+/*************** CYCLOM-Z ADDITIONS ***************/
+
+#define CZIOC           ('M' << 8)
+#define CZ_NBOARDS      (CZIOC|0xfa)
+#define CZ_BOOT_START   (CZIOC|0xfb)
+#define CZ_BOOT_DATA    (CZIOC|0xfc)
+#define CZ_BOOT_END     (CZIOC|0xfd)
+#define CZ_TEST         (CZIOC|0xfe)
+
+#define MAX_BOARD       4       /* Max number of boards */
+#define MAX_PORT        128     /* Max number of ports per board */
+#define MAX_DEV         256     /* Max number of ports total */
+
+#define CYZ_BOOT_NWORDS 0x100
+struct CYZ_BOOT_CTRL {
+        unsigned short  nboard;
+        int             status[MAX_BOARD];
+        int             nchannel[MAX_BOARD];
+        int             fw_rev[MAX_BOARD];
+        unsigned long   offset;
+        unsigned long   data[CYZ_BOOT_NWORDS];
+};
+
+
+#ifndef DP_WINDOW_SIZE
+/* #include "cyclomz.h" */
+/****************** ****************** *******************/
+/*
+ *	The data types defined below are used in all ZFIRM interface
+ *	data structures. They accomodate differences between HW
+ *	architectures and compilers.
+ */
+
+typedef unsigned long	uclong;		/* 32 bits, unsigned */
+typedef unsigned short	ucshort;	/* 16 bits, unsigned */
+typedef unsigned char	ucchar;		/* 8 bits, unsigned */
+
+/*
+ *	Memory Window Sizes
+ */
+
+#define	DP_WINDOW_SIZE		(0x00080000)	/* window size 512 Kb */
+#define	CTRL_WINDOW_SIZE	(0x00000100)	/* runtime regs 256 bytes */
+
+/*
+ *	CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver
+ *	normally will access only interested on the fpga_id, fpga_version,
+ *	start_cpu and stop_cpu.
+ */
+
+struct	CUSTOM_REG {
+	uclong	fpga_id;		/* FPGA Identification Register */
+	uclong	fpga_version;		/* FPGA Version Number Register */
+	uclong	cpu_start;		/* CPU start Register (write) */
+	uclong	cpu_stop;		/* CPU stop Register (write) */
+	uclong	misc_reg;		/* Miscelaneous Register */
+	uclong	idt_mode;		/* IDT mode Register */
+	uclong	uart_irq_status;	/* UART IRQ status Register */
+	uclong	clear_timer0_irq;	/* Clear timer interrupt Register */
+	uclong	clear_timer1_irq;	/* Clear timer interrupt Register */
+	uclong	clear_timer2_irq;	/* Clear timer interrupt Register */
+	uclong	test_register;		/* Test Register */
+	uclong	test_count;		/* Test Count Register */
+	uclong	timer_select;		/* Timer select register */
+	uclong	pr_uart_irq_status;	/* Prioritized UART IRQ stat Reg */
+	uclong	ram_wait_state;		/* RAM wait-state Register */
+	uclong	uart_wait_state;	/* UART wait-state Register */
+	uclong	timer_wait_state;	/* timer wait-state Register */
+	uclong	ack_wait_state;		/* ACK wait State Register */
+};
+
+/*
+ *	RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime
+ *	registers. This structure can be used to access the 9060 registers
+ *	(memory mapped).
+ */
+
+struct RUNTIME_9060 {
+	uclong	loc_addr_range;	/* 00h - Local Address Range */
+	uclong	loc_addr_base;	/* 04h - Local Address Base */
+	uclong	loc_arbitr;	/* 08h - Local Arbitration */
+	uclong	endian_descr;	/* 0Ch - Big/Little Endian Descriptor */
+	uclong	loc_rom_range;	/* 10h - Local ROM Range */
+	uclong	loc_rom_base;	/* 14h - Local ROM Base */
+	uclong	loc_bus_descr;	/* 18h - Local Bus descriptor */
+	uclong	loc_range_mst;	/* 1Ch - Local Range for Master to PCI */
+	uclong	loc_base_mst;	/* 20h - Local Base for Master PCI */
+	uclong	loc_range_io;	/* 24h - Local Range for Master IO */
+	uclong	pci_base_mst;	/* 28h - PCI Base for Master PCI */
+	uclong	pci_conf_io;	/* 2Ch - PCI configuration for Master IO */
+	uclong	filler1;	/* 30h */
+	uclong	filler2;	/* 34h */
+	uclong	filler3;	/* 38h */
+	uclong	filler4;	/* 3Ch */
+	uclong	mail_box_0;	/* 40h - Mail Box 0 */
+	uclong	mail_box_1;	/* 44h - Mail Box 1 */
+	uclong	mail_box_2;	/* 48h - Mail Box 2 */
+	uclong	mail_box_3;	/* 4Ch - Mail Box 3 */
+	uclong	filler5;	/* 50h */
+	uclong	filler6;	/* 54h */
+	uclong	filler7;	/* 58h */
+	uclong	filler8;	/* 5Ch */
+	uclong	pci_doorbell;	/* 60h - PCI to Local Doorbell */
+	uclong	loc_doorbell;	/* 64h - Local to PCI Doorbell */
+	uclong	intr_ctrl_stat;	/* 68h - Interrupt Control/Status */
+	uclong	init_ctrl;	/* 6Ch - EEPROM control, Init Control, etc */
+};
+
+/* Values for the Local Base Address re-map register */
+
+#define	WIN_RAM		0x00000001L	/* set the sliding window to RAM */
+#define	WIN_CREG	0x14000001L	/* set the window to custom Registers */
+
+/* Values timer select registers */
+
+#define	TIMER_BY_1M	0x00		/* clock divided by 1M */
+#define	TIMER_BY_256K	0x01		/* clock divided by 256k */
+#define	TIMER_BY_128K	0x02		/* clock divided by 128k */
+#define	TIMER_BY_32K	0x03		/* clock divided by 32k */
+
+/****************** ****************** *******************/
+#endif
+
+#ifndef ZFIRM_ID
+/* #include "zfwint.h" */
+/****************** ****************** *******************/
+/*
+ *	This file contains the definitions for interfacing with the
+ *	Cyclom-Z ZFIRM Firmware.
+ */
+
+/* General Constant definitions */
+
+#define	MAX_CHAN	64		/* max number of channels per board */
+
+/* firmware id structure (set after boot) */
+
+#define ID_ADDRESS	0x00000180L	/* signature/pointer address */
+#define	ZFIRM_ID	0x5557465AL	/* ZFIRM/U signature */
+struct	FIRM_ID {
+	uclong	signature;		/* ZFIRM/U signature */
+	uclong	zfwctrl_addr;		/* pointer to ZFW_CTRL structure */
+};
+
+/* Op. System id */
+
+#define	C_OS_LINUX	0x00000030	/* generic Linux system */
+
+/* channel op_mode */
+
+#define	C_CH_DISABLE	0x00000000	/* channel is disabled */
+#define	C_CH_TXENABLE	0x00000001	/* channel Tx enabled */
+#define	C_CH_RXENABLE	0x00000002	/* channel Rx enabled */
+#define	C_CH_ENABLE	0x00000003	/* channel Tx/Rx enabled */
+#define	C_CH_LOOPBACK	0x00000004	/* Loopback mode */
+
+/* comm_parity - parity */
+
+#define	C_PR_NONE	0x00000000	/* None */
+#define	C_PR_ODD	0x00000001	/* Odd */
+#define C_PR_EVEN	0x00000002	/* Even */
+#define C_PR_MARK	0x00000004	/* Mark */
+#define C_PR_SPACE	0x00000008	/* Space */
+#define C_PR_PARITY	0x000000ff
+
+#define	C_PR_DISCARD	0x00000100	/* discard char with frame/par error */
+#define C_PR_IGNORE	0x00000200	/* ignore frame/par error */
+
+/* comm_data_l - data length and stop bits */
+
+#define C_DL_CS5	0x00000001
+#define C_DL_CS6	0x00000002
+#define C_DL_CS7	0x00000004
+#define C_DL_CS8	0x00000008
+#define	C_DL_CS		0x0000000f
+#define C_DL_1STOP	0x00000010
+#define C_DL_15STOP	0x00000020
+#define C_DL_2STOP	0x00000040
+#define	C_DL_STOP	0x000000f0
+
+/* interrupt enabling/status */
+
+#define	C_IN_DISABLE	0x00000000	/* zero, disable interrupts */
+#define	C_IN_TXBEMPTY	0x00000001	/* tx buffer empty */
+#define	C_IN_TXLOWWM	0x00000002	/* tx buffer below LWM */
+#define	C_IN_RXHIWM	0x00000010	/* rx buffer above HWM */
+#define	C_IN_RXNNDT	0x00000020	/* rx no new data timeout */
+#define	C_IN_MDCD	0x00000100	/* modem DCD change */
+#define	C_IN_MDSR	0x00000200	/* modem DSR change */
+#define	C_IN_MRI	0x00000400	/* modem RI change */
+#define	C_IN_MCTS	0x00000800	/* modem CTS change */
+#define	C_IN_RXBRK	0x00001000	/* Break received */
+#define	C_IN_PR_ERROR	0x00002000	/* parity error */
+#define	C_IN_FR_ERROR	0x00004000	/* frame error */
+
+/* flow control */
+
+#define	C_FL_OXX	0x00000001	/* output Xon/Xoff flow control */
+#define	C_FL_IXX	0x00000002	/* output Xon/Xoff flow control */
+#define C_FL_OIXANY	0x00000004	/* output Xon/Xoff (any xon) */
+#define	C_FL_SWFLOW	0x0000000f
+
+/* flow status */
+
+#define	C_FS_TXIDLE	0x00000000	/* no Tx data in the buffer or UART */
+#define	C_FS_SENDING	0x00000001	/* UART is sending data */
+#define	C_FS_SWFLOW	0x00000002	/* Tx is stopped by received Xoff */
+
+/* rs_control/rs_status RS-232 signals */
+
+#define	C_RS_DCD	0x00000100	/* CD */
+#define	C_RS_DSR	0x00000200	/* DSR */
+#define	C_RS_RI		0x00000400	/* RI */
+#define	C_RS_CTS	0x00000800	/* CTS */
+#define	C_RS_RTS	0x00000001	/* RTS */
+#define	C_RS_DTR	0x00000004	/* DTR */
+
+/* commands Host <-> Board */
+
+#define	C_CM_RESET	0x01		/* reset/flush buffers */
+#define	C_CM_IOCTL	0x02		/* re-read CH_CTRL */
+#define	C_CM_IOCTLW	0x03		/* re-read CH_CTRL, intr when done */
+#define	C_CM_IOCTLM	0x04		/* RS-232 outputs change */
+#define	C_CM_SENDXOFF	0x10		/* send Xoff */
+#define	C_CM_SENDXON	0x11		/* send Xon */
+#define C_CM_CLFLOW	0x12		/* Clear flow control (resume) */
+#define	C_CM_SENDBRK	0x41		/* send break */
+#define	C_CM_INTBACK	0x42		/* Interrupt back */
+#define	C_CM_SET_BREAK	0x43		/* Tx break on */
+#define	C_CM_CLR_BREAK	0x44		/* Tx break off */
+#define	C_CM_CMD_DONE	0x45		/* Previous command done */
+#define	C_CM_TINACT	0x51		/* set inactivity detection */
+#define	C_CM_IRQ_ENBL	0x52		/* enable generation of interrupts */
+#define	C_CM_IRQ_DSBL	0x53		/* disable generation of interrupts */
+#define	C_CM_ACK_ENBL	0x54		/* enable acknolowdged interrupt mode */
+#define	C_CM_ACK_DSBL	0x55		/* disable acknolowdged intr mode */
+#define	C_CM_FLUSH_RX	0x56		/* flushes Rx buffer */
+#define	C_CM_FLUSH_TX	0x57		/* flushes Tx buffer */
+
+#define	C_CM_TXBEMPTY	0x60		/* Tx buffer is empty */
+#define	C_CM_TXLOWWM	0x61		/* Tx buffer low water mark */
+#define	C_CM_RXHIWM	0x62		/* Rx buffer high water mark */
+#define	C_CM_RXNNDT	0x63		/* rx no new data timeout */
+#define	C_CM_MDCD	0x70		/* modem DCD change */
+#define	C_CM_MDSR	0x71		/* modem DSR change */
+#define	C_CM_MRI	0x72		/* modem RI change */
+#define	C_CM_MCTS	0x73		/* modem CTS change */
+#define	C_CM_RXBRK	0x84		/* Break received */
+#define	C_CM_PR_ERROR	0x85		/* Parity error */
+#define	C_CM_FR_ERROR	0x86		/* Frame error */
+#define	C_CM_CMDERROR	0x90		/* command error */
+#define	C_CM_FATAL	0x91		/* fatal error */
+#define	C_CM_HW_RESET	0x92		/* reset board */
+
+/*
+ *	CH_CTRL - This per port structure contains all parameters
+ *	that control an specific port. It can be seen as the
+ *	configuration registers of a "super-serial-controller".
+ */
+
+struct CH_CTRL {
+	uclong	op_mode;	/* operation mode */
+	uclong	intr_enable;	/* interrupt masking */
+	uclong	sw_flow;	/* SW flow control */
+	uclong	flow_status;	/* output flow status */
+	uclong	comm_baud;	/* baud rate  - numerically specified */
+	uclong	comm_parity;	/* parity */
+	uclong	comm_data_l;	/* data length/stop */
+	uclong	comm_flags;	/* other flags */
+	uclong	hw_flow;	/* HW flow control */
+	uclong	rs_control;	/* RS-232 outputs */
+	uclong	rs_status;	/* RS-232 inputs */
+	uclong	flow_xon;	/* xon char */
+	uclong	flow_xoff;	/* xoff char */
+	uclong	filler[3];	/* filler to align structures */
+};
+
+
+/*
+ *	BUF_CTRL - This per channel structure contains
+ *	all Tx and Rx buffer control for a given channel.
+ */
+
+struct	BUF_CTRL	{
+	uclong	flag_dma;	/* buffers are in Host memory */
+	uclong	tx_bufaddr;	/* address of the tx buffer */
+	uclong	tx_bufsize;	/* tx buffer size */
+	uclong	tx_threshold;	/* tx low water mark */
+	uclong	tx_get;		/* tail index tx buf */
+	uclong	tx_put;		/* head index tx buf */
+	uclong	rx_bufaddr;	/* address of the rx buffer */
+	uclong	rx_bufsize;	/* rx buffer size */
+	uclong	rx_threshold;	/* rx high water mark */
+	uclong	rx_get;		/* tail index rx buf */
+	uclong	rx_put;		/* head index rx buf */
+	uclong	filler[5];	/* filler to align structures */
+};
+
+/*
+ *	BOARD_CTRL - This per board structure contains all global 
+ *	control fields related to the board.
+ */
+
+struct BOARD_CTRL {
+
+	/* static info provided by the on-board CPU */
+	uclong	n_channel;	/* number of channels */
+	uclong	fw_version;	/* firmware version */
+
+	/* static info provided by the driver */
+	uclong	op_system;	/* op_system id */
+	uclong	dr_version;	/* driver version */
+
+	/* board control area */
+	uclong	inactivity;	/* inactivity control */
+
+	/* host to FW commands */
+	uclong	hcmd_channel;	/* channel number */
+	uclong	*hcmd_param;	/* pointer to parameters */
+
+	/* FW to Host commands */
+	uclong	fwcmd_channel;	/* channel number */
+	uclong	*fwcmd_param;	/* pointer to parameters */
+
+	/* filler so the structures are aligned */
+	uclong	filler[7];
+};
+
+/*
+ *	ZFW_CTRL - This is the data structure that includes all other
+ *	data structures used by the Firmware.
+ */
+ 
+struct ZFW_CTRL {
+	struct BOARD_CTRL	board_ctrl;
+	struct CH_CTRL		ch_ctrl[MAX_CHAN];
+	struct BUF_CTRL		buf_ctrl[MAX_CHAN];
+};
+
+/****************** ****************** *******************/
+#endif
+
+
+
 #ifdef __KERNEL__
 
 /* Per card data structure */
 
 struct cyclades_card {
-    int base_addr;
+    long base_addr;
+    long ctl_addr;
     int irq;
-    int num_chips;	/* 0 if card is absent */
+    int num_chips;	/* 0 if card absent, 1 if Z/PCI, else Y */
     int first_line;	/* minor number of first channel on card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
 };
@@ -72,6 +426,7 @@
 	int			xmit_fifo_size;
 	int                     cor1,cor2,cor3,cor4,cor5;
 	int                     tbpr,tco,rbpr,rco;
+	int			baud;
 	int			ignore_status_mask;
 	int			close_delay;
 	int			IER; 	/* Interrupt Enable Register */
@@ -95,6 +450,8 @@
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
         struct cyclades_monitor mon;
+	unsigned long		jiffies[3];
+	unsigned long		rflush_count;
 };
 
 /*
@@ -111,6 +468,10 @@
 
 #define CyMaxChipsPerCard 8
 
+#define CyPCI_Ywin 0x4000
+#define CyPCI_Zctl 0x100
+#define CyPCI_Zwin 0x80000
+
 /**** CD1400 registers ****/
 
 #define CyRegSize  0x0400
@@ -282,3 +643,4 @@
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_CYCLADES_H */
+
diff -u --recursive --new-file v2.1.36/linux/include/linux/digi1.h linux/include/linux/digi1.h
--- v2.1.36/linux/include/linux/digi1.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/digi1.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,100 @@
+/*          Definitions for DigiBoard ditty(1) command.                 */
+
+#if !defined(TIOCMODG)
+#define	TIOCMODG	('d'<<8) | 250		/* get modem ctrl state	*/
+#define	TIOCMODS	('d'<<8) | 251		/* set modem ctrl state	*/
+#endif
+
+#if !defined(TIOCMSET)
+#define	TIOCMSET	('d'<<8) | 252		/* set modem ctrl state	*/
+#define	TIOCMGET	('d'<<8) | 253		/* set modem ctrl state	*/
+#endif
+
+#if !defined(TIOCMBIC)
+#define	TIOCMBIC	('d'<<8) | 254		/* set modem ctrl state */
+#define	TIOCMBIS	('d'<<8) | 255		/* set modem ctrl state */
+#endif
+
+#if !defined(TIOCSDTR)
+#define	TIOCSDTR	('e'<<8) | 0		/* set DTR		*/
+#define	TIOCCDTR	('e'<<8) | 1		/* clear DTR		*/
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA	('e'<<8) | 94		/* Read params		*/
+
+#define DIGI_SETA	('e'<<8) | 95		/* Set params		*/
+#define DIGI_SETAW	('e'<<8) | 96		/* Drain & set params	*/
+#define DIGI_SETAF	('e'<<8) | 97		/* Drain, flush & set params */
+
+#define	DIGI_GETFLOW	('e'<<8) | 99		/* Get startc/stopc flow */
+						/* control characters 	 */
+#define	DIGI_SETFLOW	('e'<<8) | 100		/* Set startc/stopc flow */
+						/* control characters	 */
+#define	DIGI_GETAFLOW	('e'<<8) | 101		/* Get Aux. startc/stopc */
+						/* flow control chars 	 */
+#define	DIGI_SETAFLOW	('e'<<8) | 102		/* Set Aux. startc/stopc */
+						/* flow control chars	 */
+
+#define	DIGI_GETINFO	('e'<<8) | 103		/* Fill in digi_info */
+#define	DIGI_POLLER	('e'<<8) | 104		/* Turn on/off poller */
+#define	DIGI_INIT	('e'<<8) | 105		/* Allow things to run. */
+
+struct	digiflow_struct 
+{
+	unsigned char	startc;				/* flow cntl start char	*/
+	unsigned char	stopc;				/* flow cntl stop char	*/
+};
+
+typedef struct digiflow_struct digiflow_t;
+
+
+/************************************************************************
+ * Values for digi_flags 
+ ************************************************************************/
+#define DIGI_IXON	0x0001		/* Handle IXON in the FEP	*/
+#define DIGI_FAST	0x0002		/* Fast baud rates		*/
+#define RTSPACE		0x0004		/* RTS input flow control	*/
+#define CTSPACE		0x0008		/* CTS output flow control	*/
+#define DSRPACE		0x0010		/* DSR output flow control	*/
+#define DCDPACE		0x0020		/* DCD output flow control	*/
+#define DTRPACE		0x0040		/* DTR input flow control	*/
+#define DIGI_FORCEDCD	0x0100		/* Force carrier		*/
+#define	DIGI_ALTPIN	0x0200		/* Alternate RJ-45 pin config	*/
+#define	DIGI_AIXON	0x0400		/* Aux flow control in fep	*/
+
+
+/************************************************************************
+ * Values for digiDload
+ ************************************************************************/
+#define NORMAL  0
+#define PCI_CTL 1
+
+#define SIZE8  0
+#define SIZE16 1
+#define SIZE32 2
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_struct 
+{
+	unsigned short	digi_flags;		/* Flags (see above)	*/
+};
+
+typedef struct digi_struct digi_t;
+
+struct digi_info 
+{
+	unsigned long board;        /* Which board is this ? */
+	unsigned char status;       /* Alive or dead */
+	unsigned char type;         /* see epca.h */
+	unsigned char subtype;      /* For future XEM, XR, etc ... */
+	unsigned short numports;    /* Number of ports configured */
+	unsigned char *port;        /* I/O Address */
+	unsigned char *membase;     /* DPR Address */
+	unsigned char *version;     /* For future ... */
+	unsigned short windowData;  /* For future ... */
+} ;
diff -u --recursive --new-file v2.1.36/linux/include/linux/digiFep1.h linux/include/linux/digiFep1.h
--- v2.1.36/linux/include/linux/digiFep1.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/digiFep1.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,136 @@
+
+#define CSTART       0x400L
+#define CMAX         0x800L
+#define ISTART       0x800L
+#define IMAX         0xC00L
+#define CIN          0xD10L
+#define GLOBAL       0xD10L
+#define EIN          0xD18L
+#define FEPSTAT      0xD20L
+#define CHANSTRUCT   0x1000L
+#define RXTXBUF      0x4000L
+
+
+struct global_data 
+{
+	volatile ushort cin;
+	volatile ushort cout;
+	volatile ushort cstart;
+	volatile ushort cmax;
+	volatile ushort ein;
+	volatile ushort eout;
+	volatile ushort istart;
+	volatile ushort imax;
+};
+
+
+struct board_chan 
+{
+	int filler1; 
+	int filler2;
+	volatile ushort tseg;
+	volatile ushort tin;
+	volatile ushort tout;
+	volatile ushort tmax;
+	
+	volatile ushort rseg;
+	volatile ushort rin;
+	volatile ushort rout;
+	volatile ushort rmax;
+	
+	volatile ushort tlow;
+	volatile ushort rlow;
+	volatile ushort rhigh;
+	volatile ushort incr;
+	
+	volatile ushort etime;
+	volatile ushort edelay;
+	volatile unchar *dev;
+	
+	volatile ushort iflag;
+	volatile ushort oflag;
+	volatile ushort cflag;
+	volatile ushort gmask;
+	
+	volatile ushort col;
+	volatile ushort delay;
+	volatile ushort imask;
+	volatile ushort tflush;
+
+	int filler3;
+	int filler4;
+	int filler5;
+	int filler6;
+	
+	volatile unchar num;
+	volatile unchar ract;
+	volatile unchar bstat;
+	volatile unchar tbusy;
+	volatile unchar iempty;
+	volatile unchar ilow;
+	volatile unchar idata;
+	volatile unchar eflag;
+	
+	volatile unchar tflag;
+	volatile unchar rflag;
+	volatile unchar xmask;
+	volatile unchar xval;
+	volatile unchar mstat;
+	volatile unchar mchange;
+	volatile unchar mint;
+	volatile unchar lstat;
+
+	volatile unchar mtran;
+	volatile unchar orun;
+	volatile unchar startca;
+	volatile unchar stopca;
+	volatile unchar startc;
+	volatile unchar stopc;
+	volatile unchar vnext;
+	volatile unchar hflow;
+
+	volatile unchar fillc;
+	volatile unchar ochar;
+	volatile unchar omask;
+
+	unchar filler7;
+	unchar filler8[28];
+}; 
+
+
+#define SRXLWATER      0xE0
+#define SRXHWATER      0xE1
+#define STOUT          0xE2
+#define PAUSETX        0xE3
+#define RESUMETX       0xE4
+#define SAUXONOFFC     0xE6
+#define SENDBREAK      0xE8
+#define SETMODEM       0xE9
+#define SETIFLAGS      0xEA
+#define SONOFFC        0xEB
+#define STXLWATER      0xEC
+#define PAUSERX        0xEE
+#define RESUMERX       0xEF
+#define SETBUFFER      0xF2
+#define SETCOOKED      0xF3
+#define SETHFLOW       0xF4
+#define SETCTRLFLAGS   0xF5
+#define SETVNEXT       0xF6
+
+
+
+#define BREAK_IND        0x01
+#define LOWTX_IND        0x02
+#define EMPTYTX_IND      0x04
+#define DATA_IND         0x08
+#define MODEMCHG_IND     0x20
+
+#define FEP_HUPCL  0002000
+#if 0
+#define RTS   0x02
+#define CD    0x08
+#define DSR   0x10
+#define CTS   0x20
+#define RI    0x40
+#define DTR   0x80
+#endif
diff -u --recursive --new-file v2.1.36/linux/include/linux/digiPCI.h linux/include/linux/digiPCI.h
--- v2.1.36/linux/include/linux/digiPCI.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/digiPCI.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,42 @@
+/*************************************************************************
+ * Defines and structure definitions for PCI BIOS Interface 
+ *************************************************************************/
+#define	PCIMAX  32		/* maximum number of PCI boards */
+
+
+#define	PCI_VENDOR_DIGI		0x114F
+#define	PCI_DEVICE_EPC		0x0002
+#define	PCI_DEVICE_RIGHTSWITCH 0x0003  /* For testing */
+#define	PCI_DEVICE_XEM		0x0004
+#define	PCI_DEVICE_XR		0x0005
+#define	PCI_DEVICE_CX		0x0006
+#define	PCI_DEVICE_XRJ		0x0009   /* Jupiter boards with */
+#define	PCI_DEVICE_EPCJ		0x000a   /* PLX 9060 chip for PCI  */
+
+
+/*
+ * On the PCI boards, there is no IO space allocated 
+ * The I/O registers will be in the first 3 bytes of the   
+ * upper 2MB of the 4MB memory space.  The board memory 
+ * will be mapped into the low 2MB of the 4MB memory space 
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE		0x00020000	
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE		0x00400000	
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE		0x00200000	
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET 		0x00200000	
+
+#define MEMOUTB(basemem, pnum, setmemval)  *(caddr_t)((basemem) + ( PCI_IO_OFFSET | pnum << 4 | pnum )) = (setmemval)
+#define MEMINB(basemem, pnum)  *(caddr_t)((basemem) + (PCI_IO_OFFSET | pnum << 4 | pnum ))   /* for PCI I/O */
+
+
+
+
+
diff -u --recursive --new-file v2.1.36/linux/include/linux/epca.h linux/include/linux/epca.h
--- v2.1.36/linux/include/linux/epca.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/epca.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,170 @@
+#define XEMPORTS    0xC02
+#define XEPORTS     0xC22
+
+#define MAX_ALLOC   0x100
+
+#define MAXBOARDS   12
+#define FEPCODESEG  0x0200L
+#define FEPCODE     0x2000L
+#define BIOSCODE    0xf800L
+
+#define MISCGLOBAL  0x0C00L
+#define NPORT       0x0C22L
+#define MBOX        0x0C40L
+#define PORTBASE    0x0C90L
+
+/* Begin code defines used for epca_setup */
+
+#define INVALID_BOARD_TYPE   0x1
+#define INVALID_NUM_PORTS    0x2
+#define INVALID_MEM_BASE     0x4
+#define INVALID_PORT_BASE    0x8
+#define INVALID_BOARD_STATUS 0x10
+#define INVALID_ALTPIN       0x20
+
+/* End code defines used for epca_setup */
+
+
+#define FEPCLR      0x00
+#define FEPMEM      0x02
+#define FEPRST      0x04
+#define FEPINT      0x08
+#define	FEPMASK     0x0e
+#define	FEPWIN      0x80
+
+#define PCXE    0
+#define PCXEVE  1
+#define PCXEM   2   
+#define EISAXEM 3
+#define PC64XE  4
+#define PCXI    5
+#define PCIXEM  7
+#define PCICX   8
+#define PCIXR   9
+#define PCIXRJ  10
+#define EPCA_NUM_TYPES 6
+
+
+static char *board_desc[] = 
+{
+	"PC/Xe",
+	"PC/Xeve",
+	"PC/Xem",
+	"EISA/Xem",
+	"PC/64Xe",
+	"PC/Xi",
+	"unknown",
+	"PCI/Xem",
+	"PCI/CX",
+	"PCI/Xr",
+	"PCI/Xrj",
+};
+
+#define STARTC      021
+#define STOPC       023
+#define IAIXON      0x2000
+
+
+#define TXSTOPPED  0x1
+#define LOWWAIT    0x2
+#define EMPTYWAIT  0x4
+#define RXSTOPPED  0x8
+#define TXBUSY     0x10
+
+#define DISABLED   0
+#define ENABLED    1
+#define OFF        0
+#define ON         1
+
+#define FEPTIMEOUT 200000  
+#define SERIAL_TYPE_NORMAL  1
+#define SERIAL_TYPE_CALLOUT 2
+#define SERIAL_TYPE_INFO    3
+#define EPCA_EVENT_HANGUP   1
+#define EPCA_MAGIC          0x5c6df104L
+
+struct channel 
+{
+	long   magic;
+	unchar boardnum;
+	unchar channelnum;
+	unchar omodem;         /* FEP output modem status     */
+	unchar imodem;         /* FEP input modem status      */
+	unchar modemfake;      /* Modem values to be forced   */
+	unchar modem;          /* Force values                */
+	unchar hflow;
+	unchar dsr;
+	unchar dcd;
+	unchar m_rts ; 		/* The bits used in whatever FEP */
+	unchar m_dcd ;		/* is indiginous to this board to */
+	unchar m_dsr ;		/* represent each of the physical */
+	unchar m_cts ;		/* handshake lines */
+	unchar m_ri ;
+	unchar m_dtr ;
+	unchar stopc;
+	unchar startc;
+	unchar stopca;
+	unchar startca;
+	unchar fepstopc;
+	unchar fepstartc;
+	unchar fepstopca;
+	unchar fepstartca;
+	unchar txwin;
+	unchar rxwin;
+	ushort fepiflag;
+	ushort fepcflag;
+	ushort fepoflag;
+	ushort txbufhead;
+	ushort txbufsize;
+	ushort rxbufhead;
+	ushort rxbufsize;
+	int    close_delay;
+	int    count;
+	int    blocked_open;
+	int    event;
+	int    asyncflags;
+	uint   dev;
+	long   session;
+	long   pgrp;
+	ulong  statusflags;
+	ulong  c_iflag;
+	ulong  c_cflag;
+	ulong  c_lflag;
+	ulong  c_oflag;
+	unchar *txptr;
+	unchar *rxptr;
+	unchar *tmp_buf;
+	struct board_info           *board;
+	volatile struct board_chan  *brdchan;
+	struct digi_struct          digiext;
+	struct tty_struct           *tty;
+	struct termios              normal_termios;
+	struct termios              callout_termios;
+	struct wait_queue           *open_wait;
+	struct wait_queue           *close_wait;
+	struct tq_struct            tqueue;
+	volatile struct global_data *mailbox;
+};
+
+struct board_info	
+{
+	unchar status;
+	unchar type;
+	unchar altpin;
+	ushort numports;
+	unchar *port;
+	unchar *membase;
+	unchar *re_map_port;
+	unchar *re_map_membase;
+	ulong  memory_seg;
+	void ( * memwinon )	(struct board_info *, unsigned int) ;
+	void ( * memwinoff ) 	(struct board_info *, unsigned int) ;
+	void ( * globalwinon )	(struct channel *) ;
+	void ( * txwinon ) 	(struct channel *) ;
+	void ( * rxwinon )	(struct channel *) ;
+	void ( * memoff )	(struct channel *) ;
+	void ( * assertgwinon )	(struct channel *) ;
+	void ( * assertmemoff )	(struct channel *) ;
+	unchar poller_inhibited ;
+};
+
diff -u --recursive --new-file v2.1.36/linux/include/linux/epcaconfig.h linux/include/linux/epcaconfig.h
--- v2.1.36/linux/include/linux/epcaconfig.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/epcaconfig.h	Mon May 12 10:35:43 1997
@@ -0,0 +1,8 @@
+#define NUMCARDS 1
+#define NBDEVS 2
+
+struct board_info static_boards[NUMCARDS]={
+	{ ENABLED, 0, OFF, 2, (unchar*) 0x320, (unchar*) 0xd0000 },
+};
+
+/* DO NOT HAND EDIT THIS FILE! */
diff -u --recursive --new-file v2.1.36/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.1.36/linux/include/linux/ext2_fs.h	Thu Feb  6 02:53:33 1997
+++ linux/include/linux/ext2_fs.h	Mon May 12 10:35:43 1997
@@ -189,6 +189,7 @@
 #define EXT2_IMMUTABLE_FL		0x00000010 /* Immutable file */
 #define EXT2_APPEND_FL			0x00000020 /* writes to file may only append */
 #define EXT2_NODUMP_FL			0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL			0x00000080 /* do not update atime */
 #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
 	
 /*
@@ -363,7 +364,10 @@
 	__u32	s_feature_compat; 	/* compatible feature set */
 	__u32	s_feature_incompat; 	/* incompatible feature set */
 	__u32	s_feature_ro_compat; 	/* readonly-compatible feature set */
-	__u32	s_reserved[230];	/* Padding to the end of the block */
+	__u8	s_uuid[16];		/* 128-bit uuid for volume */
+	char	s_volume_name[16]; 	/* volume name */
+	char	s_last_mounted[64]; 	/* directory where last mounted */
+	__u32	s_reserved[206];	/* Padding to the end of the block */
 };
 
 /*
@@ -387,6 +391,16 @@
 #define EXT2_GOOD_OLD_INODE_SIZE 128
 
 /*
+ * Feature set definitions
+ */
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+
+#define EXT2_FEATURE_COMPAT_SUPP	0
+#define EXT2_FEATURE_INCOMPAT_SUPP	0
+#define EXT2_FEATURE_RO_COMPAT_SUPP	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+
+/*
  * Default values for user and/or group using reserved blocks
  */
 #define	EXT2_DEF_RESUID		0
@@ -413,13 +427,6 @@
 #define EXT2_DIR_ROUND 			(EXT2_DIR_PAD - 1)
 #define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
 					 ~EXT2_DIR_ROUND)
-
-/*
- * Feature set definitions --- none are defined as of now
- */
-#define EXT2_FEATURE_COMPAT_SUPP	0
-#define EXT2_FEATURE_INCOMPAT_SUPP	0
-#define EXT2_FEATURE_RO_COMPAT_SUPP	0
 
 #ifdef __KERNEL__
 /*
diff -u --recursive --new-file v2.1.36/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v2.1.36/linux/include/linux/ext2_fs_sb.h	Thu Feb  6 02:53:33 1997
+++ linux/include/linux/ext2_fs_sb.h	Mon May 12 10:35:43 1997
@@ -60,6 +60,9 @@
 	int s_desc_per_block_bits;
 	int s_inode_size;
 	int s_first_ino;
+	int s_feature_compat;
+	int s_feature_incompat;
+	int s_feature_ro_compat;
 };
 
 #endif	/* _LINUX_EXT2_FS_SB */
diff -u --recursive --new-file v2.1.36/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.1.36/linux/include/linux/fb.h	Fri Apr 26 02:12:24 1996
+++ linux/include/linux/fb.h	Mon May 12 10:35:43 1997
@@ -59,6 +59,7 @@
 #define FB_ACCEL_ATARIBLITT	1	/* Atari Blitter		*/
 #define FB_ACCEL_AMIGABLITT	2	/* Amiga Blitter                */
 #define FB_ACCEL_CYBERVISION	3	/* Cybervision64 (S3 Trio64)    */
+#define FB_ACCEL_RETINAZ3	4	/* RetinaZ3 (NCR77C32BLT)       */
 
 #define FB_SYNC_HOR_HIGH_ACT	1	/* horizontal sync high active	*/
 #define FB_SYNC_VERT_HIGH_ACT	2	/* vertical sync high active	*/
@@ -205,6 +206,7 @@
    int (*switch_con)(int);          /* tell fb to switch consoles */
    int (*updatevar)(int);           /* tell fb to update the vars */
    void (*blank)(int);              /* tell fb to (un)blank the screen */
+   int (*setcmap)(struct fb_cmap *, int); /* tell fb to set the colormap */
 };
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.36/linux/include/linux/file.h linux/include/linux/file.h
--- v2.1.36/linux/include/linux/file.h	Fri Apr  4 08:52:25 1997
+++ linux/include/linux/file.h	Mon May 12 10:35:43 1997
@@ -13,16 +13,37 @@
 }
 
 extern int __fput(struct file *, struct inode *);
+extern void insert_file_free(struct file *file);
+
+/* It does not matter which list it is on. */
+extern inline void remove_filp(struct file *file)
+{
+	if(file->f_next)
+		file->f_next->f_pprev = file->f_pprev;
+	*file->f_pprev = file->f_next;
+}
 
 extern inline int fput(struct file *file, struct inode *inode)
 {
 	int count = file->f_count-1;
 	int error = 0;
 
-	if (!count)
+	if (!count) {
 		error = __fput(file, inode);
-	file->f_count = count;
+		file->f_count = 0;
+		remove_filp(file);
+		insert_file_free(file);
+	} else
+		file->f_count = count;
 	return error;
+}
+
+extern inline void put_filp(struct file *file)
+{
+	if(--file->f_count == 0) {
+		remove_filp(file);
+		insert_file_free(file);
+	}
 }
 
 #endif
diff -u --recursive --new-file v2.1.36/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.36/linux/include/linux/fs.h	Wed Apr 23 19:01:28 1997
+++ linux/include/linux/fs.h	Tue May 13 21:57:52 1997
@@ -95,7 +95,6 @@
  * Exception: MS_RDONLY is always applied to the entire file system.
  */
 #define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY))
-#define DO_UPDATE_ATIME(inode) (!((inode)->i_flags & MS_NOATIME) && !IS_RDONLY(inode))
 #define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
 #define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
 #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
@@ -105,6 +104,8 @@
 #define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE)
 #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
+#define IS_NOATIME(inode) ((inode)->i_flags & MS_NOATIME)
+#define DO_UPDATE_ATIME(inode) (!IS_NOATIME(inode) && !IS_RDONLY(inode))
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -129,7 +130,7 @@
 
 extern void buffer_init(void);
 extern void inode_init(void);
-extern unsigned long file_table_init(unsigned long start, unsigned long end);
+extern void file_table_init(void);
 extern unsigned long name_cache_init(unsigned long start, unsigned long end);
 
 typedef char buffer_block[BLOCK_SIZE];
@@ -246,6 +247,7 @@
 #define ATTR_ATIME_SET	128
 #define ATTR_MTIME_SET	256
 #define ATTR_FORCE	512	/* Not a change, but a change it */
+#define ATTR_ATTR_FLAG	1024
 
 /*
  * This is the Inode Attributes structure, used for notify_change().  It
@@ -265,8 +267,17 @@
 	time_t		ia_atime;
 	time_t		ia_mtime;
 	time_t		ia_ctime;
+	unsigned int	ia_attr_flags;
 };
 
+/*
+ * This is the inode attributes flag definitions
+ */
+#define ATTR_FLAG_SYNCRONOUS	1 	/* Syncronous write */
+#define ATTR_FLAG_NOATIME	2 	/* Don't update atime */
+#define ATTR_FLAG_APPEND	4 	/* Append-only file */
+#define ATTR_FLAG_IMMUTABLE	8 	/* Immutable file */
+
 #include <linux/quota.h>
 
 struct inode {
@@ -305,9 +316,8 @@
 	unsigned char i_dirt;
 	unsigned char i_pipe;
 	unsigned char i_sock;
-	unsigned char i_seek;
-	unsigned char i_update;
-	unsigned short i_writecount;
+	int i_writecount;
+	unsigned int i_attr_flags;
 	union {
 		struct pipe_inode_info pipe_i;
 		struct minix_inode_info minix_i;
@@ -327,17 +337,21 @@
 };
 
 struct file {
-	mode_t f_mode;
-	loff_t f_pos;
-	unsigned short f_flags;
-	unsigned short f_count;
-	unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
-	struct file *f_next, *f_prev;
-	int f_owner;		/* pid or -pgrp where SIGIO should be sent */
-	struct inode * f_inode;
-	struct file_operations * f_op;
-	unsigned long f_version;
-	void *private_data;	/* needed for tty driver, and maybe others */
+	struct file		*f_next, **f_pprev;
+	struct inode		*f_inode;
+	struct file_operations	*f_op;
+	mode_t			f_mode;
+	loff_t			f_pos;
+	unsigned short 		f_count, f_flags;
+	unsigned long 		f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+
+	/* pid or -pgrp where SIGIO should be sent */
+	int 			f_owner;
+
+	unsigned long		f_version;
+
+	/* needed for tty driver, and maybe others */
+	void			*private_data;
 };
 
 #define FL_POSIX	1
@@ -584,7 +598,7 @@
 extern int fs_may_umount(kdev_t dev, struct inode * mount_root);
 extern int fs_may_remount_ro(kdev_t dev);
 
-extern struct file *first_file;
+extern struct file *inuse_filps;
 extern struct super_block super_blocks[NR_SUPER];
 
 extern void refile_buffer(struct buffer_head * buf);
@@ -605,7 +619,7 @@
 
 extern inline void mark_buffer_clean(struct buffer_head * bh)
 {
-	if (clear_bit(BH_Dirty, &bh->b_state)) {
+	if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
 		if (bh->b_list == BUF_DIRTY)
 			refile_buffer(bh);
 	}
@@ -613,7 +627,7 @@
 
 extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
 {
-	if (!set_bit(BH_Dirty, &bh->b_state)) {
+	if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
 		set_writetime(bh, flag);
 		if (bh->b_list != BUF_DIRTY)
 			refile_buffer(bh);
diff -u --recursive --new-file v2.1.36/linux/include/linux/locks.h linux/include/linux/locks.h
--- v2.1.36/linux/include/linux/locks.h	Thu Feb  6 02:53:33 1997
+++ linux/include/linux/locks.h	Tue May 13 21:57:52 1997
@@ -22,7 +22,7 @@
 
 extern inline void lock_buffer(struct buffer_head * bh)
 {
-	while (set_bit(BH_Lock, &bh->b_state))
+	while (test_and_set_bit(BH_Lock, &bh->b_state))
 		__wait_on_buffer(bh);
 }
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/lp_m68k.h linux/include/linux/lp_m68k.h
--- v2.1.36/linux/include/linux/lp_m68k.h	Fri Dec 20 01:20:04 1996
+++ linux/include/linux/lp_m68k.h	Mon May 12 10:35:43 1997
@@ -91,7 +91,8 @@
 LP_UNKNOWN = 0,
 LP_AMIGA = 1,
 LP_ATARI = 2,
-LP_MFC = 3
+LP_MFC = 3,
+LP_IOEXT = 4
 };
 
 /*
@@ -105,10 +106,10 @@
 	int (*lp_is_busy)(int);
 	int (*lp_has_pout)(int);
 	int (*lp_is_online)(int);
-	int (*lp_my_interrupt)(int);
+	int (*lp_dummy)(int);
 	int (*lp_ioctl)(int, unsigned int, unsigned long);
-	void (*lp_open)(void);		/* for module use counter */
-	void (*lp_release)(void);	/* for module use counter */
+	int (*lp_open)(int);		/* for module use counter */
+	void (*lp_release)(int);	/* for module use counter */
 	int flags;		/*for BUSY... */
 	unsigned int chars;	/*busy timeout */
 	unsigned int time;	/*wait time */
@@ -124,7 +125,7 @@
 extern struct lp_struct *lp_table[MAX_LP];
 extern unsigned int lp_irq;
 
-void lp_interrupt(int, void *, struct pt_regs *);
+void lp_interrupt(int dev);
 int lp_init(void);
 int register_parallel(struct lp_struct *, int);
 void unregister_parallel(int);
diff -u --recursive --new-file v2.1.36/linux/include/linux/major.h linux/include/linux/major.h
--- v2.1.36/linux/include/linux/major.h	Thu Dec 19 01:03:37 1996
+++ linux/include/linux/major.h	Mon May 12 10:35:43 1997
@@ -70,6 +70,7 @@
 #define RISCOM8_NORMAL_MAJOR 48
 #define RISCOM8_CALLOUT_MAJOR 49
 #define MKISS_MAJOR	55
+#define DSP56K_MAJOR    55   /* DSP56001 processor device */
 
 /*
  * Tests for SCSI devices.
diff -u --recursive --new-file v2.1.36/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.36/linux/include/linux/mm.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/mm.h	Tue May 13 21:57:52 1997
@@ -37,18 +37,15 @@
 	unsigned long vm_end;
 	pgprot_t vm_page_prot;
 	unsigned short vm_flags;
-/* AVL tree of VM areas per task, sorted by address */
-	short vm_avl_height;
-	struct vm_area_struct * vm_avl_left;
-	struct vm_area_struct * vm_avl_right;
-/* linked list of VM areas per task, sorted by address */
-	struct vm_area_struct * vm_next;
-/* for areas with inode, the circular list inode->i_mmap */
-/* for shm areas, the circular list of attaches */
-/* otherwise unused */
-	struct vm_area_struct * vm_next_share;
-	struct vm_area_struct * vm_prev_share;
-/* more */
+	struct vm_area_struct *vm_next;
+	struct vm_area_struct **vm_pprev;
+
+	/* For areas with inode, the list inode->i_mmap, for shm areas,
+	 * the list of attaches, otherwise unused.
+	 */
+	struct vm_area_struct *vm_next_share;
+	struct vm_area_struct **vm_pprev_share;
+
 	struct vm_operations_struct * vm_ops;
 	unsigned long vm_offset;
 	struct inode * vm_inode;
@@ -264,8 +261,6 @@
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern void handle_mm_fault(struct vm_area_struct *vma, unsigned long address, int write_access);
-extern void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
-extern void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long start_mem, unsigned long end_mem);
@@ -279,8 +274,6 @@
 	unsigned long prot, unsigned long flags, unsigned long off);
 extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
 extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
-extern void remove_shared_vm_struct(struct vm_area_struct *);
-extern void build_mmap_avl(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
 extern int do_munmap(unsigned long, size_t);
 extern unsigned long get_unmapped_area(unsigned long, unsigned long);
@@ -325,38 +318,30 @@
 	return 0;
 }
 
-#define avl_empty	(struct vm_area_struct *) NULL
-
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 static inline struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
 {
-	struct vm_area_struct * result = NULL;
+	struct vm_area_struct *vma = NULL;
 
 	if (mm) {
-		struct vm_area_struct ** next = &mm->mmap_avl;
-		for (;;) {
-			struct vm_area_struct *tree = *next;
-			if (tree == avl_empty)
-				break;
-			next = &tree->vm_avl_right;
-			if (tree->vm_end <= addr)
-				continue;
-			next = &tree->vm_avl_left;
-			result = tree;
-			if (tree->vm_start <= addr)
-				break;
+		/* Check the cache first. */
+		vma = mm->mmap_cache;
+		if(!vma || (vma->vm_end <= addr) || (vma->vm_start > addr)) {
+			vma = mm->mmap;
+			while(vma && vma->vm_end <= addr)
+				vma = vma->vm_next;
+			mm->mmap_cache = vma;
 		}
 	}
-	return result;
+	return vma;
 }
 
 /* Look up the first VMA which intersects the interval start_addr..end_addr-1,
    NULL if none.  Assume start_addr < end_addr. */
 static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
 {
-	struct vm_area_struct * vma;
+	struct vm_area_struct * vma = find_vma(mm,start_addr);
 
-	vma = find_vma(mm,start_addr);
 	if (vma && end_addr <= vma->vm_start)
 		vma = NULL;
 	return vma;
diff -u --recursive --new-file v2.1.36/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.36/linux/include/linux/proc_fs.h	Sun Apr 13 10:18:22 1997
+++ linux/include/linux/proc_fs.h	Tue May 13 21:57:52 1997
@@ -162,6 +162,7 @@
 	PROC_SCSI_7000FASST,
 	PROC_SCSI_IBMMCA,
 	PROC_SCSI_EATA2X,
+	PROC_SCSI_DC390T,
 	PROC_SCSI_AM53C974,
 	PROC_SCSI_SSC,
 	PROC_SCSI_NCR53C406A,
diff -u --recursive --new-file v2.1.36/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.36/linux/include/linux/sched.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/sched.h	Tue May 13 21:57:52 1997
@@ -1,14 +1,6 @@
 #ifndef _LINUX_SCHED_H
 #define _LINUX_SCHED_H
 
-/*
- * define DEBUG if you want the wait-queues to have some extra
- * debugging code. It's not normally used, but might catch some
- * wait-queue coding errors.
- *
- *  #define DEBUG
- */
-
 #include <asm/param.h>	/* for HZ */
 
 extern unsigned long event;
@@ -149,29 +141,27 @@
 }
 
 struct mm_struct {
-	int count;
+	struct vm_area_struct *mmap, *mmap_cache;
 	pgd_t * pgd;
+	int count;
+	struct semaphore mmap_sem;
 	unsigned long context;
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack, start_mmap;
 	unsigned long arg_start, arg_end, env_start, env_end;
 	unsigned long rss, total_vm, locked_vm;
 	unsigned long def_flags;
-	struct vm_area_struct * mmap;
-	struct vm_area_struct * mmap_avl;
-	struct semaphore mmap_sem;
 };
 
-#define INIT_MM { \
-		1, \
-		swapper_pg_dir, \
-		0, \
-		0, 0, 0, 0, \
-		0, 0, 0, 0, \
-		0, 0, 0, 0, \
-		0, 0, 0, \
-		0, \
-		&init_mmap, &init_mmap, MUTEX }
+#define INIT_MM {					\
+		&init_mmap, NULL, swapper_pg_dir, 1,	\
+		MUTEX,					\
+		0,					\
+		0, 0, 0, 0,				\
+		0, 0, 0, 0,				\
+		0, 0, 0, 0,				\
+		0, 0, 0,				\
+		0 }
 
 struct signal_struct {
 	atomic_t		count;
@@ -200,8 +190,6 @@
 	struct linux_binfmt *binfmt;
 	struct task_struct *next_task, *prev_task;
 	struct task_struct *next_run,  *prev_run;
-	unsigned long saved_kernel_stack;
-	unsigned long kernel_stack_page;
 	int exit_code, exit_signal;
 	/* ??? */
 	unsigned long personality;
@@ -222,6 +210,14 @@
 	 * p->p_pptr->pid)
 	 */
 	struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+
+	/* PID hash table linkage. */
+	struct task_struct *pidhash_next;
+	struct task_struct **pidhash_pprev;
+
+	/* Pointer to task[] array linkage. */
+	struct task_struct **tarray_ptr;
+
 	struct wait_queue *wait_chldexit;	/* for wait4() */
 	unsigned short uid,euid,suid,fsuid;
 	unsigned short gid,egid,sgid,fsgid;
@@ -260,6 +256,7 @@
 /* signal handlers */
 	struct signal_struct *sig;
 /* SMP state */
+	int has_cpu;
 	int processor;
 	int last_processor;
 	int lock_depth;		/* Lock depth. We can context switch in and out of holding a syscall kernel lock... */	
@@ -294,6 +291,16 @@
 
 #define DEF_PRIORITY	(20*HZ/100)	/* 200 ms time slices */
 
+/* Note: This is very ugly I admit.  But some versions of gcc will
+ *       dump core when an empty structure constant is parsed at
+ *       the end of a large top level structure initialization. -DaveM
+ */
+#ifdef __SMP__
+#define INIT_LOCKS	SPIN_LOCK_UNLOCKED
+#else
+#define INIT_LOCKS
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -304,11 +311,13 @@
 /* exec domain */&default_exec_domain, \
 /* binfmt */	NULL, \
 /* schedlink */	&init_task,&init_task, &init_task, &init_task, \
-/* stack */	0,(unsigned long) &init_kernel_stack, \
 /* ec,brk... */	0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0,0, \
 /* suppl grps*/ 0, {0,}, \
-/* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \
+/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
+/* pidhash */	NULL, NULL, \
+/* tarray */	&task[0], \
+/* chld wait */	NULL, \
 /* uid etc */	0,0,0,0,0,0,0,0, \
 /* timeout */	0,SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
@@ -326,14 +335,88 @@
 /* files */	&init_files, \
 /* mm */	&init_mm, \
 /* signals */	&init_signals, \
-/* SMP */	0,0,0, \
+/* SMP */	0,0,0,0, \
+/* locks */	INIT_LOCKS \
 }
 
+union task_union {
+	struct task_struct task;
+	unsigned long stack[2048];
+};
+
+extern union task_union init_task_union;
+
 extern struct   mm_struct init_mm;
-extern struct task_struct init_task;
 extern struct task_struct *task[NR_TASKS];
 extern struct task_struct *last_task_used_math;
 
+extern struct task_struct **tarray_freelist;
+extern spinlock_t taskslot_lock;
+
+extern __inline__ void add_free_taskslot(struct task_struct **t)
+{
+	spin_lock(&taskslot_lock);
+	*t = (struct task_struct *) tarray_freelist;
+	tarray_freelist = t;
+	spin_unlock(&taskslot_lock);
+}
+
+extern __inline__ struct task_struct **get_free_taskslot(void)
+{
+	struct task_struct **tslot;
+
+	spin_lock(&taskslot_lock);
+	if((tslot = tarray_freelist) != NULL)
+		tarray_freelist = (struct task_struct **) *tslot;
+	spin_unlock(&taskslot_lock);
+
+	return tslot;
+}
+
+/* PID hashing. */
+#define PIDHASH_SZ (NR_TASKS >> 2)
+extern struct task_struct *pidhash[PIDHASH_SZ];
+extern spinlock_t pidhash_lock;
+
+#define pid_hashfn(x)	((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
+
+extern __inline__ void hash_pid(struct task_struct *p)
+{
+	struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+
+	spin_lock(&pidhash_lock);
+	if((p->pidhash_next = *htable) != NULL)
+		(*htable)->pidhash_pprev = &p->pidhash_next;
+	*htable = p;
+	p->pidhash_pprev = htable;
+	spin_unlock(&pidhash_lock);
+}
+
+extern __inline__ void unhash_pid(struct task_struct *p)
+{
+	spin_lock(&pidhash_lock);
+	if(p->pidhash_next)
+		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
+	*p->pidhash_pprev = p->pidhash_next;
+	spin_unlock(&pidhash_lock);
+}
+
+extern __inline__ struct task_struct *find_task_by_pid(int pid)
+{
+	struct task_struct **htable = &pidhash[pid_hashfn(pid)];
+	struct task_struct *p;
+
+	spin_lock(&pidhash_lock);
+	for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
+		;
+	spin_unlock(&pidhash_lock);
+
+	return p;
+}
+
+/* per-UID process charging. */
+extern int charge_uid(struct task_struct *p, int count);
+
 #include <asm/current.h>
 
 extern unsigned long volatile jiffies;
@@ -425,15 +508,15 @@
 	wait->next = next;
 }
 
-extern spinlock_t waitqueue_lock;
+extern rwlock_t waitqueue_lock;
 
 extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&waitqueue_lock, flags);
+	write_lock_irqsave(&waitqueue_lock, flags);
 	__add_wait_queue(p, wait);
-	spin_unlock_irqrestore(&waitqueue_lock, flags);
+	write_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
 extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
@@ -454,9 +537,9 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&waitqueue_lock, flags);
+	write_lock_irqsave(&waitqueue_lock, flags);
 	__remove_wait_queue(p, wait);
-	spin_unlock_irqrestore(&waitqueue_lock, flags); 
+	write_unlock_irqrestore(&waitqueue_lock, flags); 
 }
 
 extern inline void poll_wait(struct wait_queue ** wait_address, poll_table * p)
diff -u --recursive --new-file v2.1.36/linux/include/linux/serial.h linux/include/linux/serial.h
--- v2.1.36/linux/include/linux/serial.h	Tue Mar  4 10:25:26 1997
+++ linux/include/linux/serial.h	Mon May 12 17:40:38 1997
@@ -46,7 +46,8 @@
 #define PORT_16650	6
 #define PORT_16650V2	7
 #define PORT_16750	8
-#define PORT_MAX	8
+#define PORT_STARTECH	9
+#define PORT_MAX	9
 
 struct serial_uart_config {
 	char	*name;
diff -u --recursive --new-file v2.1.36/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.36/linux/include/linux/skbuff.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/skbuff.h	Tue May 13 21:57:53 1997
@@ -123,6 +123,9 @@
 #endif
 };
 
+/* These are just the default values. This is run time configurable.
+ * FIXME: Probably the config option should go away. -- erics
+ */
 #ifdef CONFIG_SKB_LARGE
 #define SK_WMEM_MAX	65535
 #define SK_RMEM_MAX	65535
diff -u --recursive --new-file v2.1.36/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.1.36/linux/include/linux/slab.h	Thu Feb  6 02:53:33 1997
+++ linux/include/linux/slab.h	Tue May 13 21:57:52 1997
@@ -54,6 +54,7 @@
 
 /* System wide slabs. */
 extern kmem_cache_t *vm_area_cachep;
+extern kmem_cache_t *mm_cachep;
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.1.36/linux/include/linux/smp.h	Sun Jan 26 05:36:05 1997
+++ linux/include/linux/smp.h	Mon May 12 10:35:44 1997
@@ -47,6 +47,7 @@
  
 #define smp_num_cpus			1
 #define smp_processor_id()		0
+#define hard_smp_processor_id()		0
 #define smp_message_pass(t,m,d,w)	
 #define smp_threads_ready		1
 #define kernel_lock()
diff -u --recursive --new-file v2.1.36/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.36/linux/include/linux/socket.h	Thu Mar 27 14:40:11 1997
+++ linux/include/linux/socket.h	Mon May 12 10:35:44 1997
@@ -3,8 +3,8 @@
 
 #include <asm/socket.h>			/* arch-dependent defines	*/
 #include <linux/sockios.h>		/* the SIOCxxx I/O controls	*/
-#include <linux/uio.h>			/* iovec support		*/
 #include <linux/types.h>		/* pid_t			*/
+#include <linux/uio.h>			/* iovec support		*/
 
 typedef unsigned short	sa_family_t;
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.36/linux/include/linux/sysctl.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/sysctl.h	Mon May 12 10:35:44 1997
@@ -104,6 +104,13 @@
 
 
 /* /proc/sys/net/core */
+enum
+{
+	NET_CORE_WMEM_MAX=1,
+	NET_CORE_RMEM_MAX,
+	NET_CORE_WMEM_DEFAULT,
+	NET_CORE_RMEM_DEFAULT,
+};
 
 /* /proc/sys/net/ethernet */
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v2.1.36/linux/include/linux/tqueue.h	Thu Mar 27 14:40:11 1997
+++ linux/include/linux/tqueue.h	Mon May 12 17:40:37 1997
@@ -83,7 +83,7 @@
 extern __inline__ void queue_task(struct tq_struct *bh_pointer,
 			   task_queue *bh_list)
 {
-	if (!set_bit(0,&bh_pointer->sync)) {
+	if (!test_and_set_bit(0,&bh_pointer->sync)) {
 		unsigned long flags;
 		spin_lock_irqsave(&tqueue_lock, flags);
 		bh_pointer->next = *bh_list;
diff -u --recursive --new-file v2.1.36/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.1.36/linux/include/linux/tty.h	Fri Apr  4 08:52:26 1997
+++ linux/include/linux/tty.h	Tue May 13 21:57:52 1997
@@ -288,6 +288,7 @@
 extern int pty_init(void);
 extern int tty_init(void);
 extern int pcxe_init(void);
+extern int pc_init(void);
 extern int vcs_init(void);
 extern int cy_init(void);
 extern int stl_init(void);
@@ -330,10 +331,14 @@
 /* serial.c */
 
 extern long serial_console_init(long kmem_start, long kmem_end);
-
+ 
 /* pcxx.c */
 
 extern int pcxe_open(struct tty_struct *tty, struct file *filp);
+
+/* epca.c */
+
+extern int pc_open(struct tty_struct *tty, struct file *filp);
 
 /* console.c */
 
diff -u --recursive --new-file v2.1.36/linux/include/linux/zorro.h linux/include/linux/zorro.h
--- v2.1.36/linux/include/linux/zorro.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/zorro.h	Mon May 12 10:35:44 1997
@@ -637,642 +637,3 @@
 #endif	/* __KERNEL__ */
 
 #endif /* __ZORRO_H */
-/*
- * linux/zorro.h -- Amiga AutoConfig (Zorro) Expansion Device Definitions
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef __ZORRO_H
-#define __ZORRO_H
-
-#ifndef __ASSEMBLY__
-
-/*
- * Defined Board Manufacturers
- *
- * Please update arch/m68k/amiga/zorro.c if you make changes here
- * Many IDs were obtained from ExpName/Identify ((C) Richard Körber)
- * and by looking at the NetBSD-Amiga kernel sources
- */
-
-#define MANUF_PACIFIC          (0x00D3)	/* Pacific Peripherals */
-#define PROD_SE_2000_A500      (0x00)	/* SE 2000 A500 */
-#define PROD_PACIFIC_HD        (0x0A)	/* HD Controller */
-
-#define MANUF_KUPKE            (0x00DD)	/* Kupke */
-#define PROD_GOLEM_BOX_2       (0x00)	/* Golem RAM Box 2MB */
-
-#define MANUF_MEMPHIS          (0x0100)	/* Memphis */
-#define PROD_STORMBRINGER      (0x00)	/* Stormbringer */
-
-#define MANUF_3_STATE          (0x0200)	/* 3-State */
-#define PROD_MEGAMIX_2000      (0x02)	/* Megamix 2000 RAM */
-
-#define MANUF_COMMODORE2       (0x0201)	/* Commodore Braunschweig */
-#define PROD_A2088             (0x01)	/* CBM A2088 XT Bridgeboard */
-#define PROD_A2286             (0x02)	/* CBM A2286 AT Bridgeboard */
-#define PROD_A4091_2           (0x54)	/* CBM A4091 SCSI Controller */
-#define PROD_A2386SX           (0x67)	/* CBM A2386-SX Bridgeboard */
-
-#define MANUF_COMMODORE        (0x0202)	/* Commodore West Chester */
-#define PROD_A2090A            (0x01)	/* CBM A2090/A2090A HD Controller */
-#define PROD_A590              (0x02)	/* CBM A590 SCSI Controller */
-#define PROD_A2091             (0x03)	/* CBM A2091 SCSI Controller */
-#define PROD_A2090B            (0x04)	/* CBM A2090B 2090 Autoboot Card */
-#define PROD_ARCNET            (0x09)	/* CBM A2060 Arcnet Card */
-#define PROD_CBMRAM            (0x0A)	/* CBM A2052/58.RAM | 590/2091.RAM */
-#define PROD_A560RAM           (0x20)	/* CBM A560 Memory Module */
-#define PROD_A2232PROTO        (0x45)	/* CBM A2232 Serial Prototype */
-#define PROD_A2232             (0x46)	/* CBM A2232 Serial Production */
-#define PROD_A2620             (0x50)	/* CBM A2620 68020/RAM Card */
-#define PROD_A2630             (0x51)	/* CBM A2630 68030/RAM Card */
-#define PROD_A4091             (0x54)	/* CBM A4091 SCSI Controller */
-#define PROD_A2065_2           (0x5A)	/* A2065 Ethernet Card */
-#define PROD_ROMULATOR         (0x60)	/* CBM Romulator Card */
-#define PROD_A3000TESTFIX      (0x61)	/* CBM A3000 Test Fixture */
-#define PROD_A2386SX_2         (0x67)	/* A2386-SX Bridgeboard */
-#define PROD_A2065             (0x70)	/* CBM A2065 Ethernet Card */
-
-#define MANUF_COMMODORE3       (0x0203)	/* Commodore West Chester */
-#define PROD_A2090A_CM         (0x03)	/* A2090A Combitec/MacroSystem */
-
-#define MANUF_KCS              (0x02FF)	/* Kolff Computer Supplies */
-#define PROD_POWER_BOARD       (0x00)	/* KCS Power PC Board */
-
-#define MANUF_CARDCO           (0x03EC)	/* Cardco */
-#define PROD_KRONOS_2000_SCSI  (0x04)	/* Kronos 2000 SCSI Controller */
-#define PROD_A1000_SCSI        (0x0C)	/* A1000 SCSI Controller */
-#define PROD_ESCORT_SCSI       (0x0E)	/* Escort SCSI Controller */
-#define PROD_CC_A2410          (0xF5)	/* Cardco A2410 Hires Graphics Card */
-
-#define MANUF_A_SQUARED        (0x03ED)	/* A-Squared */
-#define PROD_LIVE_2000         (0x01)	/* Live! 2000 */
-
-#define MANUF_COMSPEC          (0x03EE)	/* ComSpec Communications */
-#define PROD_AX2000            (0x01)	/* AX2000 */
-
-#define MANUF_ANAKIN           (0x03F1)	/* Anakin */
-#define PROD_EASYL             (0x01)	/* Easyl Tablet */
-
-#define MANUF_MICROBOTICS      (0x03F2)	/* MicroBotics */
-#define PROD_STARBOARD_II      (0x00)	/* StarBoard II */
-#define PROD_STARDRIVE         (0x02)	/* StarDrive */
-#define PROD_8_UP_A            (0x03)	/* 8-Up (Rev A) */
-#define PROD_8_UP_Z            (0x04)	/* 8-Up (Rev Z) */
-#define PROD_DELTA_RAM         (0x20)	/* Delta Card RAM */
-#define PROD_8_STAR_RAM        (0x40)	/* 8-Star RAM */
-#define PROD_8_STAR            (0x41)	/* 8-Star */
-#define PROD_VXL_RAM           (0x44)	/* VXL RAM */
-#define PROD_VXL_30            (0x45)	/* VXL-30 Turbo Board */
-#define PROD_DELTA             (0x60)	/* Delta Card */
-#define PROD_MBX_1200          (0x81)	/* MBX 1200 */
-#define PROD_HARDFRAME_2000    (0x9E)	/* Hardframe 2000 */
-#define PROD_MBX_1200_2        (0xC1)	/* MBX 1200 */
-
-#define MANUF_ACCESS           (0x03F4)	/* Access Associates */
-
-#define MANUF_EXPANSION_TECH   (0x03F6)	/* Expansion Technologies */
-
-#define MANUF_ASDG             (0x03FF)	/* ASDG */
-#define PROD_ASDG_MEMORY       (0x01)	/* Memory Expansion */
-#define PROD_ASDG_MEMORY_2     (0x02)	/* Memory Expansion */
-#define PROD_LAN_ROVER         (0xFE)	/* Lan Rover Ethernet */
-#define PROD_TWIN_X            (0xFF)	/* Twin-X Serial Card */
-
-#define MANUF_IMTRONICS        (0x0404)	/* Imtronics */
-#define PROD_HURRICANE_2800    (0x39)	/* Hurricane 2800 68030 */
-#define PROD_HURRICANE_2800_2  (0x57)	/* Hurricane 2800 68030 */
-
-#define MANUF_UNIV_OF_LOWELL   (0x0406)	/* University of Lowell */
-#define PROD_A2410             (0x00)	/* CBM A2410 Hires Graphics Card */
-
-#define MANUF_AMERISTAR        (0x041D)	/* Ameristar */
-#define PROD_AMERISTAR2065     (0x01)	/* A2065 Ethernet Card */
-#define PROD_A560              (0x09)	/* Arcnet Card */
-#define PROD_A4066             (0x0A)	/* A4066 Ethernet Card */
-
-#define MANUF_SUPRA            (0x0420)	/* Supra */
-#define PROD_SUPRADRIVE_4x4    (0x01)	/* SupraDrive 4x4 SCSI Controller */
-#define PROD_SUPRA_2000        (0x03)	/* 2000 DMA HD */
-#define PROD_SUPRA_500         (0x05)	/* 500 HD/RAM */
-#define PROD_SUPRA_500XP       (0x09)	/* 500XP/2000 RAM */
-#define PROD_SUPRA_500RX       (0x0A)	/* 500RX/2000 RAM */
-#define PROD_SUPRA_2400ZI      (0x0B)	/* 2400zi Modem */
-#define PROD_WORDSYNC          (0x0C)	/* Supra Wordsync SCSI Controller */
-#define PROD_WORDSYNC_II       (0x0D)	/* Supra Wordsync II SCSI Controller */
-#define PROD_SUPRA_2400ZIPLUS  (0x10)	/* 2400zi+ Modem */
-
-#define MANUF_CSA              (0x0422)	/* Computer Systems Ass. */
-#define PROD_MAGNUM            (0x11)	/* Magnum 40 SCSI Controller */
-#define PROD_12GAUGE           (0x15)	/* 12 Gauge SCSI Controller */
-
-#define MANUF_MTEC2            (0x0502)	/* M-Tech */
-#define PROD_AT500_2           (0x03)	/* AT500 RAM */
-
-#define MANUF_GVP3             (0x06E1)	/* Great Valley Products */
-#define PROD_IMPACT            (0x08)	/* Impact SCSI/Memory */
-
-#define MANUF_BYTEBOX          (0x07DA)	/* ByteBox */
-#define PROD_BYTEBOX_A500      (0x00)	/* A500 */
-
-#define MANUF_HACKER           (0x07DB)	/* Test only: no product definitions */
-
-#define MANUF_POWER_COMPUTING  (0x07DC)	/* Power Computing (DKB) */
-#define PROD_DKB_3128          (0x0E)	/* DKB 3128 RAM */
-#define PROD_RAPID_FIRE        (0x0F)	/* Rapid Fire SCSI Controller */
-#define PROD_DKB_1202          (0x10)	/* DKB 1202 RAM */
-#define PROD_VIPER_II_COBRA    (0x12)	/* Viper II Turbo Board (DKB Cobra) */
-#define PROD_WILDFIRE_060      (0x17)	/* WildFire 060 Turbo Board */
-#define PROD_WILDFIRE_060_2    (0xFF)	/* WildFire 060 Turbo Board */
-
-#define MANUF_GVP              (0x07E1)	/* Great Valley Products */
-#define PROD_IMPACT_I_4K       (0x01)	/* Impact Series-I SCSI 4K */
-#define PROD_IMPACT_I_16K_2    (0x02)	/* Impact Series-I SCSI 16K/2 */
-#define PROD_IMPACT_I_16K_3    (0x03)	/* Impact Series-I SCSI 16K/3 */
-#define PROD_IMPACT_3001_IDE   (0x08)	/* Impact 3001 IDE */
-#define PROD_IMPACT_3001_RAM   (0x09)	/* Impact 3001 RAM */
-#define PROD_GVPIISCSI         (0x0B)	/* GVP Series II SCSI Controller */
-#define PROD_GVPIISCSI_2       (0x09)	/* evidence that the driver works
-					   for this product code also */
-#define PROD_GVPIIRAM          (0x0A)	/* GVP Series II RAM */
-#define PROD_GVP               (0x0B)	/* This code is used by a wide range of
-					   GVP products - use the epc to
-					   identify it correctly */
-#define PROD_GVP_A2000_030     (0x0D)	/* GVP A2000 68030 Turbo Board */
-#define PROD_IMPACT_3001_IDE_2 (0x0D)	/* Impact 3001 IDE */
-#define PROD_GFORCE_040_SCSI   (0x16)	/* GForce 040 with SCSI (new) */
-#define PROD_GVPIV_24          (0x20)	/* GVP IV-24 Graphics Board */
-#define PROD_GFORCE_040        (0xFF)	/* GForce 040 Turbo Board */
-/* #define PROD_GVPIO_EXT      (0xFF)*/	/* GVP I/O Extender */
-
-#define MANUF_SYNERGY          (0x07E5)	/* Synergy */
-
-#define MANUF_XETEC            (0x07E6)	/* Xetec */
-#define PROD_FASTCARD_SCSI     (0x01)	/* FastCard SCSI Controller */
-#define PROD_FASTCARD_RAM      (0x02)	/* FastCard RAM */
-
-#define MANUF_PPI              (0x07EA)	/* Progressive Peripherals Inc. */
-#define PROD_MERCURY           (0x00)	/* Mercury Turbo Board */
-#define PROD_PPS_A3000_040     (0x01)	/* PP&S A3000 68040 Turbo Board */
-#define PROD_PPS_A2000_040     (0x69)	/* PP&S A2000 68040 Turbo Board */
-#define PROD_ZEUS              (0x96)	/* Zeus SCSI Controller */
-#define PROD_PPS_A500_040      (0xBB)	/* PP&S A500 68040 Turbo Board */
-
-#define MANUF_XEBEC            (0x07EC)	/* Xebec */
-
-#define MANUF_SPIRIT           (0x07F2)	/* Spirit */
-#define PROD_HDA_506           (0x04)	/* HDA 506 Harddisk */
-#define PROD_OCTABYTE_RAM      (0x06)	/* OctaByte RAM */
-
-#define MANUF_BSC              (0x07FE)	/* BSC */
-#define PROD_ALF_3_SCSI        (0x03)	/* BSC ALF 3 SCSI Controller */
-
-#define MANUF_BSC3             (0x0801)	/* BSC */
-#define PROD_ALF_2_SCSI        (0x01)	/* ALF 2 SCSI Controller */
-#define PROD_ALF_2_SCSI_2      (0x02)	/* ALF 2 SCSI Controller */
-#define PROD_ALF_3_SCSI_2      (0x03)	/* ALF 3 SCSI Controller */
-
-#define MANUF_C_LTD            (0x0802)	/* C Ltd. */
-#define PROD_KRONOS_SCSI       (0x04)	/* Kronos SCSI Controller */
-#define PROD_A1000_SCSI_2      (0x0C)	/* A1000 SCSI Controller */
-
-#define MANUF_JOCHHEIM         (0x0804)	/* Jochheim */
-#define PROD_JOCHHEIM_RAM      (0x01)	/* Jochheim RAM */
-
-#define MANUF_CHECKPOINT       (0x0807)	/* Checkpoint Technologies */
-#define PROD_SERIAL_SOLUTION   (0x00)	/* Serial Solution */
-
-#define MANUF_ICD              (0x0817)	/* ICD */
-#define PROD_ADVANTAGE_2000    (0x01)	/* Advantage 2000 SCSI Controller */
-
-#define MANUF_KUPKE2           (0x0819)	/* Kupke */
-#define PROD_KUPKE_SCSI_II     (0x02)	/* Golem SCSI-II Controller */
-#define PROD_GOLEM_BOX         (0x03)	/* Golem Box */
-#define PROD_KUPKE_TURBO       (0x04)	/* 030/882 Turbo Board */
-#define PROD_KUPKE_SCSI_AT     (0x05)	/* SCSI/AT Controller */
-
-#define MANUF_GVP4             (0x081D)	/* Great Valley Products */
-#define PROD_A2000_RAM8        (0x09)	/* A2000-RAM8/2 */
-
-#define MANUF_INTERWORKS_NET   (0x081E)	/* Interworks Network */
-
-#define MANUF_HARDITAL         (0x0820)	/* Hardital Synthesis */
-#define PROD_TQM               (0x14)	/* TQM 68030+68882 Turbo Board */
-
-#define MANUF_BSC2             (0x082C)	/* BSC */
-#define PROD_OKTAGON_SCSI      (0x05)	/* BSC Oktagon 2008 SCSI Controller */
-#define PROD_TANDEM            (0x06)	/* BSC Tandem AT-2008/508 IDE */
-#define PROD_ALPHA_RAM_1200    (0x07)	/* Alpha RAM 1200 */
-#define PROD_OKTAGON_RAM       (0x08)	/* BSC Oktagon 2008 RAM */
-#define PROD_MULTIFACE_I       (0x10)	/* Alfa Data MultiFace I */
-#define PROD_MULTIFACE_II      (0x11)	/* Alfa Data MultiFace II */
-#define PROD_MULTIFACE_III     (0x12)	/* Alfa Data MultiFace III */
-#define PROD_BSC_FRAEMBUFFER   (0x20)	/* Framebuffer */
-#define PROD_GRAFFITI_RAM      (0x21)	/* Graffiti Graphics Board */
-#define PROD_GRAFFITI_REG      (0x22)
-#define PROD_ISDN_MASTERCARD   (0x40)	/* BSC ISDN MasterCard */
-#define PROD_ISDN_MASTERCARD_2 (0x41)	/* BSC ISDN MasterCard II */
-
-#define MANUF_ADV_SYS_SOFT     (0x0836)	/* Advanced Systems & Software */
-#define PROD_NEXUS_SCSI        (0x01)	/* Nexus SCSI Controller */
-#define PROD_NEXUS_RAM         (0x08)	/* Nexus RAM */
-
-#define MANUF_IMPULSE          (0x0838)	/* Impulse */
-#define PROD_FIRECRACKER_24    (0x00)	/* FireCracker 24 */
-
-#define MANUF_IVS              (0x0840)	/* IVS */
-#define PROD_GRANDSLAM_PIC_2   (0x02)	/* GrandSlam PIC 2 RAM */
-#define PROD_GRANDSLAM_PIC_1   (0x04)	/* GrandSlam PIC 1 RAM */
-#define PROD_IVS_OVERDRIVE     (0x10)	/* OverDrive HD */
-#define PROD_TRUMPCARD_CLASSIC (0x30)	/* Trumpcard Classic SCSI Controller */
-#define PROD_TRUMPCARD_PRO     (0x34)	/* Trumpcard Pro SCSI Controller */
-#define PROD_META_4            (0x40)	/* Meta-4 RAM */
-#define PROD_WAVETOOLS         (0xBF)	/* Wavetools Sound Board */
-#define PROD_VECTOR            (0xF3)	/* Vector SCSI Controller */
-#define PROD_VECTOR_2          (0xF4)	/* Vector SCSI Controller */
-
-#define MANUF_VECTOR           (0x0841)	/* Vector */
-#define PROD_CONNECTION        (0xE3)	/* Connection Serial IO */
-
-#define MANUF_XPERT_PRODEV     (0x0845)	/* XPert/ProDev */
-#define PROD_VISIONA_RAM       (0x01)	/* Visiona Graphics Board */
-#define PROD_VISIONA_REG       (0x02)
-#define PROD_MERLIN_RAM        (0x03)	/* Merlin Graphics Board */
-#define PROD_MERLIN_REG        (0x04)
-#define PROD_MERLIN_REG_2      (0xC9)
-
-#define MANUF_HYDRA_SYSTEMS    (0x0849)	/* Hydra Systems */
-#define PROD_AMIGANET          (0x01)	/* Amiganet Board */
-
-#define MANUF_SUNRIZE          (0x084F)	/* Sunrize Industries */
-#define PROD_AD1012            (0x01)	/* AD1012 Sound Board */
-#define PROD_AD516             (0x02)	/* AD516 Sound Board */
-#define PROD_DD512             (0x03)	/* DD512 Sound Board */
-
-#define MANUF_TRICERATOPS      (0x0850)	/* Triceratops */
-#define PROD_TRICERATOPS       (0x01)	/* Triceratops Multi I/O Board */
-
-#define MANUF_APPLIED_MAGIC    (0x0851)	/* Applied Magic Inc */
-#define PROD_DMI_RESOLVER      (0x01)	/* DMI Resolver Graphics Board */
-#define PROD_DIGITAL_BCASTER   (0x06)	/* Digital Broadcaster */
-
-#define MANUF_GFX_BASE         (0x085E)	/* GFX-Base */
-#define PROD_GDA_1_RAM         (0x00)	/* GDA-1 Graphics Board */
-#define PROD_GDA_1_REG         (0x01)
-
-#define MANUF_ROCTEC           (0x0860)	/* RocTec */
-#define PROD_RH_800C           (0x01)	/* RH 800C Hard Disk Controller */
-#define PROD_RH_800C_RAM       (0x01)	/* RH 800C RAM */
-
-#define MANUF_HELFRICH1        (0x0861)	/* Helfrich */
-#define PROD_RAINBOW3          (0x21)	/* Rainbow3 Graphics Board */
-
-#define MANUF_SW_RESULT_ENTS   (0x0866)	/* Software Result Enterprises */
-#define PROD_GG2PLUS           (0x01)	/* GG2+ Bus Converter */
-
-#define MANUF_MASOBOSHI        (0x086D)	/* Masoboshi */
-#define PROD_MASTER_CARD_RAM   (0x03)	/* Master Card RAM */
-#define PROD_MASTER_CARD_SCSI  (0x04)	/* Master Card SCSI Controller */
-#define PROD_MVD_819           (0x07)	/* MVD 819 */
-
-#define MANUF_DELACOMP         (0x0873)	/* DelaComp */
-#define PROD_DELACOMP_RAM_2000 (0x01)	/* RAM Expansion 2000 */
-
-#define MANUF_VILLAGE_TRONIC   (0x0877)	/* Village Tronic */
-#define PROD_DOMINO_RAM        (0x01)	/* Domino Graphics Board */
-#define PROD_DOMINO_REG        (0x02)
-#define PROD_PICASSO_II_RAM    (0x0B)	/* Picasso II/II+ Graphics Board */
-#define PROD_PICASSO_II_REG    (0x0C)
-#define PROD_PICASSO_II_SEGM   (0x0D)	/* Picasso II/II+ (Segmented Mode) */
-#define PROD_PICASSO_IV        (0x15)	/* Picassio IV Graphics Board */
-#define PROD_PICASSO_IV_2      (0x16)
-#define PROD_PICASSO_IV_3      (0x17)
-#define PROD_PICASSO_IV_4      (0x18)
-#define PROD_ARIADNE           (0xC9)	/* Ariadne Ethernet */
-
-#define MANUF_UTILITIES_ULTD   (0x087B)	/* Utilities Unlimited */
-#define PROD_EMPLANT_DELUXE    (0x15)	/* Emplant Deluxe SCSI Controller */
-#define PROD_EMPLANT_DELUXE2   (0x20)	/* Emplant Deluxe SCSI Controller */
-
-#define MANUF_AMITRIX          (0x0880)	/* Amitrix */
-#define PROD_AMITRIX_MULTI_IO  (0x01)	/* Multi-IO */
-#define PROD_AMITRIX_CD_RAM    (0x02)	/* CD-RAM Memory */
-
-#define MANUF_ARMAX            (0x0885)	/* ArMax */
-#define PROD_OMNIBUS           (0x00)	/* OmniBus Graphics Board */
-
-#define MANUF_NEWTEK           (0x088F)	/* NewTek */
-#define PROD_VIDEOTOASTER      (0x00)	/* VideoToaster */
-
-#define MANUF_MTEC             (0x0890)	/* M-Tech Germany */
-#define PROD_AT500             (0x01)	/* AT500 IDE Controller */
-#define PROD_MTEC_68030        (0x03)	/* 68030 Turbo Board */
-#define PROD_MTEC_68020I       (0x06)	/* 68020i Turbo Board */
-#define PROD_MTEC_T1230        (0x20)	/* A1200 T68030/42 RTC Turbo Board */
-#define PROD_MTEC_RAM          (0x22)	/* MTEC 8MB RAM */
-
-#define MANUF_GVP2             (0x0891)	/* Great Valley Products */
-#define PROD_SPECTRUM_RAM      (0x01)	/* EGS 28/24 Spectrum Graphics Board */
-#define PROD_SPECTRUM_REG      (0x02)
-
-#define MANUF_HELFRICH2        (0x0893)	/* Helfrich */
-#define PROD_PICCOLO_RAM       (0x05)	/* Piccolo Graphics Board */
-#define PROD_PICCOLO_REG       (0x06)
-#define PROD_PEGGY_PLUS        (0x07)	/* PeggyPlus MPEG Decoder Board */
-#define PROD_VIDEOCRUNCHER     (0x08)	/* VideoCruncher */
-#define PROD_SD64_RAM          (0x0A)	/* SD64 Graphics Board */
-#define PROD_SD64_REG          (0x0B)
-
-#define MANUF_MACROSYSTEMS     (0x089B)	/* MacroSystems USA */
-#define PROD_WARP_ENGINE       (0x13)	/* Warp Engine 40xx SCSI Controller */
-
-#define MANUF_ELBOX            (0x089E)	/* ElBox Computer */
-#define PROD_ELBOX_1200        (0x06)	/* Elbox 1200/4 RAM */
-
-#define MANUF_HARMS_PROF       (0x0A00)	/* Harms Professional */
-#define PROD_HARMS_030_PLUS    (0x10)	/* 030 plus */
-#define PROD_3500_TURBO        (0xD0)	/* 3500 Turbo board */
-
-#define MANUF_MICRONIK         (0x0A50)	/* Micronik */
-#define PROD_RCA_120           (0x0A)	/* RCA 120 RAM */
-
-#define MANUF_MEGA_MICRO       (0x1000)	/* MegaMicro */
-#define PROD_SCRAM_500_SCSI    (0x03)	/* SCRAM 500 SCSI Controller */
-#define PROD_SCRAM_500_RAM     (0x04)	/* SCRAM 500 RAM */
-
-#define MANUF_IMTRONICS2       (0x1028)	/* Imtronics */
-#define PROD_HURRICANE_2800_3  (0x39)	/* Hurricane 2800 68030 */
-#define PROD_HURRICANE_2800_4  (0x57)	/* Hurricane 2800 68030 */
-
-#define MANUF_KUPKE3           (0x1248)	/* Kupke */
-#define PROD_GOLEM_3000        (0x01)	/* Golem HD 3000 */
-
-#define MANUF_ITH              (0x1388)	/* ITH */
-#define PROD_ISDN_MASTER_II    (0x01)	/* ISDN-Master II */
-
-#define MANUF_VMC              (0x1389)	/* VMC */
-#define PROD_ISDN_BLASTER_Z2   (0x01)	/* ISDN Blaster Z2 */
-#define PROD_HYPERCOM_4        (0x02)	/* HyperCom 4 */
-
-#define MANUF_INFORMATION      (0x157C)	/* Information */
-#define PROD_ISDN_ENGINE_I     (0x64)	/* ISDN Engine I */
-
-#define MANUF_VORTEX           (0x2017)	/* Vortex */
-#define PROD_GOLDEN_GATE_386SX (0x07)	/* Golden Gate 80386SX Board */
-#define PROD_GOLDEN_GATE_RAM   (0x08)	/* Golden Gate RAM */
-#define PROD_GOLDEN_GATE_486   (0x09)	/* Golden Gate 80486 Board */
-
-#define MANUF_DATAFLYER        (0x2062)	/* DataFlyer */
-#define PROD_DATAFLYER_4000SXS (0x01)	/* DataFlyer 4000SX SCSI Controller */
-#define PROD_DATAFLYER_4000SXR (0x02)	/* DataFlyer 4000SX RAM */
-
-#define MANUF_READYSOFT        (0x2100)	/* ReadySoft */
-#define PROD_AMAX              (0x01)	/* AMax II/IV */
-
-#define MANUF_PHASE5           (0x2140)	/* Phase5 */
-#define PROD_BLIZZARD_RAM      (0x01)	/* Blizzard RAM */
-#define PROD_BLIZZARD          (0x02)	/* Blizzard */
-#define PROD_BLIZZARD_1220_IV  (0x06)	/* Blizzard 1220-IV Turbo Board */
-#define PROD_FASTLANE_RAM      (0x0A)	/* FastLane RAM */
-#define PROD_FASTLANE_SCSI     (0x0B)	/* FastLane/Blizzard 1230-II SCSI/CyberSCSI */
-#define PROD_CYBERSTORM_SCSI   (0x0C)	/* Blizzard 1220/CyberStorm */
-#define PROD_BLIZZARD_1230_III (0x0D)	/* Blizzard 1230-III Turbo Board */
-#define PROD_BLIZZARD_1230_IV  (0x11)	/* Blizzard 1230-IV/1260 Turbo Board */
-#define PROD_BLIZZARD_2060SCSI (0x18)	/* Blizzard 2060 SCSI Controller */
-#define PROD_CYBERSTORM_II     (0x19)	/* CyberStorm Mk II */
-#define PROD_CYBERVISION       (0x22)	/* CyberVision64 Graphics Board */
-#define PROD_CYBERVISION3D_PRT (0x32)	/* CyberVision64-3D Prototype */
-#define PROD_CYBERVISION3D     (0x43)	/* CyberVision64-3D Graphics Board */
-
-#define MANUF_DPS              (0x2169)	/* DPS */
-#define PROD_DPS_PAR           (0x01)	/* Personal Animation Recorder */
-
-#define MANUF_APOLLO2          (0x2200)	/* Apollo */
-#define PROD_A620              (0x00)	/* A620 68020 Accelerator */
-#define PROD_A620_2            (0x01)	/* A620 68020 Accelerator */
-
-#define MANUF_APOLLO           (0x2222)	/* Apollo */
-#define PROD_AT_APOLLO         (0x22)	/* AT-Apollo */
-#define PROD_APOLLO_TURBO      (0x23)	/* Apollo Turbo Board */
-
-#define MANUF_PETSOFF          (0x38A5)	/* Petsoff LP */
-#define PROD_DELFINA           (0x00)	/* Delfina DSP */
-
-#define MANUF_UWE_GERLACH      (0x3FF7)	/* Uwe Gerlach */
-#define PROD_UG_RAM_ROM        (0xd4)	/* RAM/ROM */
-
-#define MANUF_MACROSYSTEMS2    (0x4754)	/* MacroSystems Germany */
-#define PROD_MAESTRO           (0x03)	/* Maestro */
-#define PROD_VLAB              (0x04)	/* VLab */
-#define PROD_MAESTRO_PRO       (0x05)	/* Maestro Pro */
-#define PROD_RETINA_Z2         (0x06)	/* Retina Z2 Graphics Board */
-#define PROD_MULTI_EVOLUTION   (0x08)	/* MultiEvolution */
-#define PROD_TOCCATA           (0x0C)	/* Toccata Sound Board */
-#define PROD_RETINA_Z3         (0x10)	/* Retina Z3 Graphics Board */
-#define PROD_VLAB_MOTION       (0x12)	/* VLab Motion */
-#define PROD_ALTAIS            (0x13)	/* Altais Graphics Board */
-#define PROD_FALCON_040        (0xFD)	/* Falcon '040 Turbo Board */
-
-#define MANUF_COMBITEC         (0x6766)	/* Combitec */
-
-#define MANUF_SKI              (0x8000)	/* SKI Peripherals */
-#define PROD_MAST_FIREBALL     (0x08)	/* M.A.S.T. Fireball SCSI Controller */
-#define PROD_SKI_SCSI_SERIAL   (0x80)	/* SCSI / Dual Serial */
-
-#define MANUF_CAMERON          (0xAA01)	/* Cameron */
-#define PROD_PERSONAL_A4       (0x10)	/* Personal A4 */
-
-#define MANUF_REIS_WARE        (0xAA11)	/* Reis-Ware */
-#define PROD_RW_HANDYSCANNER   (0x11)	/* Handyscanner */
-
-
-/* Illegal Manufacturer IDs. These do NOT appear in arch/m68k/amiga/zorro.c! */
-
-#define MANUF_HACKER_INC       (0x07DB)	/* Hacker Inc. */
-#define PROD_HACKER_SCSI       (0x01)	/* Hacker Inc. SCSI Controller */
-
-#define MANUF_RES_MNGT_FORCE   (0x07DB)	/* Resource Management Force */
-#define PROD_QUICKNET          (0x02)	/* QuickNet Ethernet */
-
-#define MANUF_VECTOR2          (0x07DB)	/* Vector */
-#define PROD_CONNECTION_2      (0xE0)	/* Vector Connection */
-#define PROD_CONNECTION_3      (0xE1)	/* Vector Connection */
-#define PROD_CONNECTION_4      (0xE2)	/* Vector Connection */
-#define PROD_CONNECTION_5      (0xE3)	/* Vector Connection */
-
-
-/*
- * GVP's identifies most of their product through the 'extended
- * product code' (epc). The epc has to be and'ed with the GVP_PRODMASK
- * before the identification.
- */
-
-#define GVP_PRODMASK    (0xf8)
-#define GVP_SCSICLKMASK (0x01)
-
-enum GVP_ident {
-  GVP_GFORCE_040      = 0x20,
-  GVP_GFORCE_040_SCSI = 0x30,
-  GVP_A1291_SCSI      = 0x40,
-  GVP_COMBO_R4        = 0x60,
-  GVP_COMBO_R4_SCSI   = 0x70,
-  GVP_PHONEPAK        = 0x78,
-  GVP_IOEXT           = 0x98,
-  GVP_GFORCE_030      = 0xa0,
-  GVP_GFORCE_030_SCSI = 0xb0,
-  GVP_A530            = 0xc0,
-  GVP_A530_SCSI       = 0xd0,
-  GVP_COMBO_R3        = 0xe0,
-  GVP_COMBO_R3_SCSI   = 0xf0,
-  GVP_SERIESII        = 0xf8,
-};
-
-enum GVP_flags {
-  GVP_IO       = 0x01,
-  GVP_ACCEL    = 0x02,
-  GVP_SCSI     = 0x04,
-  GVP_24BITDMA = 0x08,
-  GVP_25BITDMA = 0x10,
-  GVP_NOBANK   = 0x20,
-  GVP_14MHZ    = 0x40,
-};
-
-
-struct Node {
-    struct  Node *ln_Succ;	/* Pointer to next (successor) */
-    struct  Node *ln_Pred;	/* Pointer to previous (predecessor) */
-    u_char  ln_Type;
-    char    ln_Pri;		/* Priority, for sorting */
-    char    *ln_Name;		/* ID string, null terminated */
-};
-
-struct ExpansionRom {
-    /* -First 16 bytes of the expansion ROM */
-    u_char	er_Type;	/* Board type, size and flags */
-    u_char	er_Product;	/* Product number, assigned by manufacturer */
-    u_char	er_Flags;	/* Flags */
-    u_char	er_Reserved03;	/* Must be zero ($ff inverted) */
-    u_short	er_Manufacturer; /* Unique ID,ASSIGNED BY COMMODORE-AMIGA! */
-    u_long	er_SerialNumber; /* Available for use by manufacturer */
-    u_short	er_InitDiagVec;	/* Offset to optional "DiagArea" structure */
-    u_char	er_Reserved0c;
-    u_char	er_Reserved0d;
-    u_char	er_Reserved0e;
-    u_char	er_Reserved0f;
-};
-
-/* er_Type board type bits */
-#define ERT_TYPEMASK	0xc0
-#define ERT_ZORROII	0xc0
-#define ERT_ZORROIII	0x80
-
-/* other bits defined in er_Type */
-#define ERTB_MEMLIST	5		/* Link RAM into free memory list */
-#define ERTF_MEMLIST	(1<<5)
-
-struct ConfigDev {
-    struct Node 	cd_Node;
-    u_char		cd_Flags;	/* (read/write) */
-    u_char		cd_Pad; 	/* reserved */
-    struct ExpansionRom cd_Rom; 	/* copy of board's expansion ROM */
-    void		*cd_BoardAddr;	/* where in memory the board was placed */
-    u_long		cd_BoardSize;	/* size of board in bytes */
-    u_short		cd_SlotAddr;	/* which slot number (PRIVATE) */
-    u_short		cd_SlotSize;	/* number of slots (PRIVATE) */
-    void		*cd_Driver;	/* pointer to node of driver */
-    struct ConfigDev	*cd_NextCD;	/* linked list of drivers to config */
-    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__
-
-#define ZORRO_NUM_AUTO		16
-
-#ifdef __KERNEL__
-
-extern int zorro_num_autocon;		/* # of autoconfig devices found */
-extern struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
-
-
-/*
- * Zorro Functions
- */
-
-extern int zorro_find(int manuf, int prod, int part, int index);
-extern struct ConfigDev *zorro_get_board(int key);
-extern void zorro_config_board(int key, int part);
-extern void zorro_unconfig_board(int key, int part);
-
-
-/*
- * Bitmask indicating portions of available Zorro II RAM that are unused
- * by the system. Every bit represents a 64K chunk, for a maximum of 8MB
- * (128 chunks, physical 0x00200000-0x009fffff).
- *
- * If you want to use (= allocate) portions of this RAM, you should clear
- * the corresponding bits.
- */
-
-extern u_long zorro_unused_z2ram[4];
-
-#define Z2RAM_START		(0x00200000)
-#define Z2RAM_END		(0x00a00000)
-#define Z2RAM_SIZE		(0x00800000)
-#define Z2RAM_CHUNKSIZE		(0x00010000)
-#define Z2RAM_CHUNKMASK		(0x0000ffff)
-#define Z2RAM_CHUNKSHIFT	(16)
-
-
-/*
- * Verbose Board Identification
- */
-
-extern void zorro_identify(void);
-extern int zorro_get_list(char *buffer);
-
-#endif	/* !__ASSEMBLY__ */
-#endif	/* __KERNEL__ */
-
-#endif /* __ZORRO_H */
diff -u --recursive --new-file v2.1.36/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.36/linux/include/net/sock.h	Wed Apr 23 19:01:29 1997
+++ linux/include/net/sock.h	Tue May 13 21:58:38 1997
@@ -216,6 +216,7 @@
  *      Options received (usually on last packet, some only on SYN packets).
  */
 	char	tstamp_ok,	/* TIMESTAMP seen on SYN packet		*/
+		wscale_ok,	/* Wscale seen on SYN packet		*/
 		sack_ok;	/* SACK_PERM seen on SYN packet		*/
 	char	saw_tstamp;	/* Saw TIMESTAMP on last packet		*/
         __u16	in_mss;		/* MSS option received from sender	*/
diff -u --recursive --new-file v2.1.36/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.36/linux/include/net/tcp.h	Wed Apr 23 19:01:29 1997
+++ linux/include/net/tcp.h	Tue May 13 22:00:15 1997
@@ -43,6 +43,17 @@
 extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
 extern struct sock *tcp_bound_hash[TCP_BHTABLE_SIZE];
 
+/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
+ * because the v6 tcp code to intialize a connection needs to interoperate
+ * with the v4 code using the same variables.
+ * FIXME: It would be better to rewrite the connection code to be
+ * address family independent and just leave one copy in the ipv4 section.
+ * This would also clean up some code duplication. -- erics
+ */
+extern int sysctl_tcp_sack;
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+
 /* These are AF independant. */
 static __inline__ int tcp_bhashfn(__u16 lport)
 {
@@ -224,8 +235,12 @@
 	__u16			rmt_port;
 	__u16			mss;
 	__u8			snd_wscale;
+	__u8			rcv_wscale;
 	char			sack_ok;
 	char			tstamp_ok;
+	char			wscale_ok;
+	__u32			window_clamp;	/* window clamp at creation time */
+	__u32			rcv_wnd;	/* rcv_wnd offered first time */
 	__u32			ts_recent;
 	unsigned long		expires;
 	int			retrans;
@@ -452,6 +467,10 @@
 
 extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX];
  
+/*
+ * FIXME: this method of choosing when to send a window update
+ * does not seem correct to me. -- erics
+ */
 static __inline__ unsigned short tcp_raise_window(struct sock *sk)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -553,9 +572,9 @@
  * It would be especially magical to compute the checksum for this
  * stuff on the fly here.
  */
-extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int wscale)
+extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int offer_wscale, int wscale)
 {
-	int count = 4 + (wscale ? 4 : 0) +  ((ts || sack) ? 4 : 0) +  (ts ? 8 : 0);
+	int count = 4 + (offer_wscale ? 4 : 0) +  ((ts || sack) ? 4 : 0) +  (ts ? 8 : 0);
 	unsigned char *optr = skb_put(skb,count);
 	__u32 *ptr = (__u32 *)optr;
 
@@ -579,10 +598,51 @@
 		*ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
 				| (TCPOPT_NOP << 8) | TCPOPT_NOP);
 	}
-	if (wscale)
-		*ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | wscale);
+	if (offer_wscale)
+		*ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | (wscale << 8));
 	skb->csum = csum_partial(optr, count, 0);
 	return count;
+}
+
+/* Determine a window scaling and initial window to offer.
+ * Based on the assumption that the given amount of space
+ * will be offered. Store the results in the tp structure.
+ * NOTE: for smooth operation initial space offering should
+ * be a multiple of mss if possible. We assume here that mss >= 1.
+ * This MUST be enforced by all callers.
+ */
+extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
+	__u32 *rcv_wnd,
+	__u32 *window_clamp,
+	int wscale_ok,
+	__u8 *rcv_wscale)
+{
+	/* If no clamp set the clamp to the max possible scaled window */
+	if (*window_clamp == 0)
+		(*window_clamp) = (65535<<14);
+	space = min(*window_clamp,space);
+
+	/* Quantize space offering to a multiple of mss if possible. */
+	if (space > mss)
+		space = (space/mss)*mss;
+
+	/* NOTE: offering an initial window larger than 32767
+	 * will break some buggy TCP stacks. We try to be nice.
+	 * If we are not window scaling, then this truncates
+	 * our initial window offering to 32k. There should also
+	 * be a sysctl option to stop being nice.
+	 */
+	(*rcv_wnd) = min(space,32767);
+	(*rcv_wscale) = 0;
+	if (wscale_ok) {
+		/* See RFC1323 for an explanation of the limit to 14 */
+		while (space > 65535 && (*rcv_wscale) < 14) {
+			space >>= 1;
+			(*rcv_wscale)++;
+		}
+	}
+	/* Set the clamp no higher than max representable value */
+	(*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
 }
 
 extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req)
diff -u --recursive --new-file v2.1.36/linux/init/main.c linux/init/main.c
--- v2.1.36/linux/init/main.c	Wed Apr 23 19:01:29 1997
+++ linux/init/main.c	Mon May 12 10:35:44 1997
@@ -68,6 +68,7 @@
 extern long console_init(long, long);
 extern long kmalloc_init(long,long);
 extern void sock_init(void);
+extern void uidcache_init(void);
 extern unsigned long pci_init(unsigned long, unsigned long);
 extern long mca_init(long, long);
 extern long sbus_init(long, long);
@@ -175,6 +176,9 @@
 #ifdef CONFIG_ISDN_DRV_HISAX
 extern void HiSax_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_DIGIEPCA
+extern void epca_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_ISDN_DRV_PCBIT
 extern void pcbit_setup(char *str, int *ints);
 #endif
@@ -191,6 +195,9 @@
 extern void wd33c93_setup (char *str, int *ints);
 extern void gvp11_setup (char *str, int *ints);
 
+#ifdef CONFIG_CYCLADES
+extern void cy_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_DIGI
 extern void pcxx_setup(char *str, int *ints);
 #endif
@@ -257,7 +264,7 @@
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 
-__initfunc(char *get_options(char *str, int *ints))
+char *get_options(char *str, int *ints)
 {
 	char *cur = str;
 	int i=1;
@@ -478,9 +485,15 @@
 #if defined(CONFIG_GVP11_SCSI)
 	{ "gvp11=", gvp11_setup },
 #endif
+#ifdef CONFIG_CYCLADES
+	{ "cyclades=", cy_setup },
+#endif
 #ifdef CONFIG_DIGI
 	{ "digi=", pcxx_setup },
 #endif
+#ifdef CONFIG_DIGIEPCA
+	{ "digiepca=", epca_setup },
+#endif
 #ifdef CONFIG_RISCOM8
 	{ "riscom8=", riscom8_setup },
 #endif
@@ -638,6 +651,7 @@
 		{ "gscd",    0x1000 },
 		{ "sbpcd",   0x1900 },
 		{ "sonycd",  0x1800 },
+		{ "eda",     0x2400 },
 		{ "eza",     0x2800 },
 		{ "bpcd",    0x2900 },
 #if CONFIG_APBLOCK
@@ -779,43 +793,11 @@
  
 extern int cpu_idle(void * unused);
 
-/*
- *	Activate a secondary processor.
- */
- 
-__initfunc(asmlinkage void start_secondary(void))
-{
-	trap_init();
-	init_IRQ();
-	smp_callin();
-	cpu_idle(NULL);
-}
-
-
-
 /* Called by boot processor to activate the rest. */
 __initfunc(static void smp_init(void))
 {
-	int i, j;
-
 	/* Get other processors into their bootup holding patterns. */
 	smp_boot_cpus();
-
-	/* Create the slave init tasks as sharing pid 0.  This should only
-	 * happen if we have virtual CPU numbers higher than 0.
-	 */
-	for (i=1; i<smp_num_cpus; i++)
-	{
-		/* We use kernel_thread for the idlers which are
-		 * unlocked tasks running in kernel space.
-		 */
-		kernel_thread(cpu_idle, NULL, CLONE_PID);
-
-		/* Don't assume linear processor numbering */
-		j = cpu_logical_map[i];
-		current_set[j]=task[i];
-		current_set[j]->processor=j;
-	}
 }		
 
 /*
@@ -832,6 +814,8 @@
 	
 #endif
 
+extern void initialize_secondary(void);
+
 /*
  *	Activate the first processor.
  */
@@ -840,18 +824,14 @@
 {
 	char * command_line;
 
-/*
- *	This little check will move.
- */
-
 #ifdef __SMP__
-	static int first_cpu=1;
-	
-	if(!first_cpu)
-		start_secondary();
-	first_cpu=0;
-	
-#endif	
+	static int boot_cpu = 1;
+	/* "current" has been set up, we need to load it now */
+	if (!boot_cpu)
+		initialize_secondary();
+	boot_cpu = 0;
+#endif
+
 /*
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
@@ -896,7 +876,6 @@
 	memory_start = kmem_cache_init(memory_start, memory_end);
 	sti();
 	calibrate_delay();
-	memory_start = file_table_init(memory_start,memory_end);
 	memory_start = name_cache_init(memory_start,memory_end);
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
@@ -910,9 +889,11 @@
 	proc_root_init();
 #endif
 	kmem_cache_sizes_init();
+	uidcache_init();
 	vma_init();
 	buffer_init();
 	inode_init();
+	file_table_init();
 	sock_init();
 #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
 	ipc_init();
diff -u --recursive --new-file v2.1.36/linux/ipc/msg.c linux/ipc/msg.c
--- v2.1.36/linux/ipc/msg.c	Mon Apr 14 16:28:26 1997
+++ linux/ipc/msg.c	Mon May 12 10:35:44 1997
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -39,7 +40,7 @@
 static int kerneld_arr[MAX_KERNELDS];
 static int n_kernelds = 0;
 
-void msg_init (void)
+__initfunc(void msg_init (void))
 {
 	int id;
 	
diff -u --recursive --new-file v2.1.36/linux/ipc/sem.c linux/ipc/sem.c
--- v2.1.36/linux/ipc/sem.c	Sun Jan 26 02:07:48 1997
+++ linux/ipc/sem.c	Mon May 12 10:35:44 1997
@@ -40,6 +40,7 @@
 #include <linux/malloc.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -55,7 +56,7 @@
 
 static unsigned short sem_seq = 0;
 
-void sem_init (void)
+__initfunc(void sem_init (void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/ipc/shm.c linux/ipc/shm.c
--- v2.1.36/linux/ipc/shm.c	Mon Apr 14 16:28:26 1997
+++ linux/ipc/shm.c	Mon May 12 10:35:44 1997
@@ -16,6 +16,7 @@
 #include <linux/swap.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -44,7 +45,7 @@
 static ulong swap_successes = 0;
 static ulong used_segs = 0;
 
-void shm_init (void)
+__initfunc(void shm_init (void))
 {
 	int id;
 
@@ -402,42 +403,21 @@
 	shm_swap_in		/* swapin */
 };
 
-/* Insert shmd into the circular list shp->attaches */
+/* Insert shmd into the list shp->attaches */
 static inline void insert_attach (struct shmid_ds * shp, struct vm_area_struct * shmd)
 {
-	struct vm_area_struct * attaches;
-
-	if ((attaches = shp->attaches)) {
-		shmd->vm_next_share = attaches;
-		shmd->vm_prev_share = attaches->vm_prev_share;
-		shmd->vm_prev_share->vm_next_share = shmd;
-		attaches->vm_prev_share = shmd;
-	} else
-		shp->attaches = shmd->vm_next_share = shmd->vm_prev_share = shmd;
+	if((shmd->vm_next_share = shp->attaches) != NULL)
+		shp->attaches->vm_pprev_share = &shmd->vm_next_share;
+	shp->attaches = shmd;
+	shmd->vm_pprev_share = &shp->attaches;
 }
 
-/* Remove shmd from circular list shp->attaches */
+/* Remove shmd from list shp->attaches */
 static inline void remove_attach (struct shmid_ds * shp, struct vm_area_struct * shmd)
 {
-	if (shmd->vm_next_share == shmd) {
-		if (shp->attaches != shmd) {
-			printk("shm_close: shm segment (id=%ld) attach list inconsistent\n",
-			       SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK);
-			printk("shm_close: %08lx-%08lx %c%c%c%c %08lx %08lx\n",
-				shmd->vm_start, shmd->vm_end,
-				shmd->vm_flags & VM_READ ? 'r' : '-',
-				shmd->vm_flags & VM_WRITE ? 'w' : '-',
-				shmd->vm_flags & VM_EXEC ? 'x' : '-',
-				shmd->vm_flags & VM_MAYSHARE ? 's' : 'p',
-				shmd->vm_offset, shmd->vm_pte);
-		}
-		shp->attaches = NULL;
-	} else {
-		if (shp->attaches == shmd)
-			shp->attaches = shmd->vm_next_share;
-		shmd->vm_prev_share->vm_next_share = shmd->vm_next_share;
-		shmd->vm_next_share->vm_prev_share = shmd->vm_prev_share;
-	}
+	if(shmd->vm_next_share)
+		shmd->vm_next_share->vm_pprev_share = shmd->vm_pprev_share;
+	*shmd->vm_pprev_share = shmd->vm_next_share;
 }
 
 /*
@@ -575,7 +555,6 @@
 	shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
 			 | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
 			 | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
-	shmd->vm_next_share = shmd->vm_prev_share = NULL;
 	shmd->vm_inode = NULL;
 	shmd->vm_offset = 0;
 	shmd->vm_ops = &shm_vm_ops;
@@ -825,9 +804,10 @@
 		if (shmd->vm_mm->rss > 0)
 			shmd->vm_mm->rss--;
 		flush_tlb_page(shmd, tmp);
-	    /* continue looping through circular list */
+	    /* continue looping through the linked list */
 	    } while (0);
-	    if ((shmd = shmd->vm_next_share) == shp->attaches)
+	    shmd = shmd->vm_next_share;
+	    if (!shmd)
 		break;
 	}
 
diff -u --recursive --new-file v2.1.36/linux/ipc/util.c linux/ipc/util.c
--- v2.1.36/linux/ipc/util.c	Mon Oct 28 04:21:41 1996
+++ linux/ipc/util.c	Mon May 12 10:35:44 1997
@@ -11,6 +11,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -18,7 +19,7 @@
 
 extern void sem_init (void), msg_init (void), shm_init (void);
 
-void ipc_init (void)
+__initfunc(void ipc_init (void))
 {
 	sem_init();
 	msg_init();
diff -u --recursive --new-file v2.1.36/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.36/linux/kernel/exit.c	Wed Apr 23 19:01:29 1997
+++ linux/kernel/exit.c	Mon May 12 10:35:44 1997
@@ -4,8 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#undef DEBUG_PROC_TREE
-
 #include <linux/config.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
@@ -16,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
@@ -124,132 +123,29 @@
 	wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
 }
 
-void release(struct task_struct * p)
+static void release(struct task_struct * p)
 {
-	int i;
-
-	if (!p)
-		return;
-	if (p == current) {
-		printk("task releasing itself\n");
-		return;
-	}
-	for (i=1 ; i<NR_TASKS ; i++)
-		if (task[i] == p) {
+	if (p != current) {
 #ifdef __SMP__
-			/* FIXME! Cheesy, but kills the window... -DaveM */
-			while(p->processor != NO_PROC_ID)
-				barrier();
-			spin_unlock_wait(&scheduler_lock);
+		/* FIXME! Cheesy, but kills the window... -DaveM */
+		while (p->has_cpu)
+			barrier();
+		spin_unlock_wait(&scheduler_lock);
 #endif
-			nr_tasks--;
-			task[i] = NULL;
-			REMOVE_LINKS(p);
-			release_thread(p);
-			if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
-				printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
-			free_kernel_stack(p->kernel_stack_page);
-			current->cmin_flt += p->min_flt + p->cmin_flt;
-			current->cmaj_flt += p->maj_flt + p->cmaj_flt;
-			current->cnswap += p->nswap + p->cnswap;
-			free_task_struct(p);
-			return;
-		}
-	panic("trying to release non-existent task");
-}
-
-#ifdef DEBUG_PROC_TREE
-/*
- * Check to see if a task_struct pointer is present in the task[] array
- * Return 0 if found, and 1 if not found.
- */
-int bad_task_ptr(struct task_struct *p)
-{
-	int 	i;
-
-	if (!p)
-		return 0;
-	for (i=0 ; i<NR_TASKS ; i++)
-		if (task[i] == p)
-			return 0;
-	return 1;
-}
-
-/*
- * This routine scans the pid tree and makes sure the rep invariant still
- * holds.  Used for debugging only, since it's very slow....
- *
- * It looks a lot scarier than it really is.... we're doing nothing more
- * than verifying the doubly-linked list found in p_ysptr and p_osptr,
- * and checking it corresponds with the process tree defined by p_cptr and
- * p_pptr;
- */
-void audit_ptree(void)
-{
-	int	i;
-
-	for (i=1 ; i<NR_TASKS ; i++) {
-		if (!task[i])
-			continue;
-		if (bad_task_ptr(task[i]->p_pptr))
-			printk("Warning, pid %d's parent link is bad\n",
-				task[i]->pid);
-		if (bad_task_ptr(task[i]->p_cptr))
-			printk("Warning, pid %d's child link is bad\n",
-				task[i]->pid);
-		if (bad_task_ptr(task[i]->p_ysptr))
-			printk("Warning, pid %d's ys link is bad\n",
-				task[i]->pid);
-		if (bad_task_ptr(task[i]->p_osptr))
-			printk("Warning, pid %d's os link is bad\n",
-				task[i]->pid);
-		if (task[i]->p_pptr == task[i])
-			printk("Warning, pid %d parent link points to self\n",
-				task[i]->pid);
-		if (task[i]->p_cptr == task[i])
-			printk("Warning, pid %d child link points to self\n",
-				task[i]->pid);
-		if (task[i]->p_ysptr == task[i])
-			printk("Warning, pid %d ys link points to self\n",
-				task[i]->pid);
-		if (task[i]->p_osptr == task[i])
-			printk("Warning, pid %d os link points to self\n",
-				task[i]->pid);
-		if (task[i]->p_osptr) {
-			if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
-				printk(
-			"Warning, pid %d older sibling %d parent is %d\n",
-				task[i]->pid, task[i]->p_osptr->pid,
-				task[i]->p_osptr->p_pptr->pid);
-			if (task[i]->p_osptr->p_ysptr != task[i])
-				printk(
-		"Warning, pid %d older sibling %d has mismatched ys link\n",
-				task[i]->pid, task[i]->p_osptr->pid);
-		}
-		if (task[i]->p_ysptr) {
-			if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
-				printk(
-			"Warning, pid %d younger sibling %d parent is %d\n",
-				task[i]->pid, task[i]->p_osptr->pid,
-				task[i]->p_osptr->p_pptr->pid);
-			if (task[i]->p_ysptr->p_osptr != task[i])
-				printk(
-		"Warning, pid %d younger sibling %d has mismatched os link\n",
-				task[i]->pid, task[i]->p_ysptr->pid);
-		}
-		if (task[i]->p_cptr) {
-			if (task[i]->p_cptr->p_pptr != task[i])
-				printk(
-			"Warning, pid %d youngest child %d has mismatched parent link\n",
-				task[i]->pid, task[i]->p_cptr->pid);
-			if (task[i]->p_cptr->p_ysptr)
-				printk(
-			"Warning, pid %d youngest child %d has non-NULL ys link\n",
-				task[i]->pid, task[i]->p_cptr->pid);
-		}
+		charge_uid(p, -1);
+		nr_tasks--;
+		add_free_taskslot(p->tarray_ptr);
+		unhash_pid(p);
+		REMOVE_LINKS(p);
+		release_thread(p);
+		current->cmin_flt += p->min_flt + p->cmin_flt;
+		current->cmaj_flt += p->maj_flt + p->cmaj_flt;
+		current->cnswap += p->nswap + p->cnswap;
+		free_task_struct(p);
+	} else {
+		printk("task releasing itself\n");
 	}
 }
-#endif /* DEBUG_PROC_TREE */
 
 /*
  * This checks not only the pgrp, but falls back on the pid if no
@@ -347,17 +243,12 @@
 
 	retval = -EINVAL;
 	if (sig >= 0 && sig <= 32) {
-		struct task_struct *p;
+		struct task_struct *p = find_task_by_pid(pid);
 		
-		retval = -ESRCH;
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid != pid)
-				continue;
-			retval = send_sig(sig,p,priv);
-			break;
-		}
-		read_unlock(&tasklist_lock);
+		if(p)
+			retval = send_sig(sig, p, priv);
+		else
+			retval = -ESRCH;
 	}
 	return retval;
 }
@@ -550,7 +441,7 @@
 		if (!--mm->count) {
 			exit_mmap(mm);
 			free_page_tables(mm);
-			kfree(mm);
+			kmem_cache_free(mm_cachep, mm);
 		}
 	}
 }
diff -u --recursive --new-file v2.1.36/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.36/linux/kernel/fork.c	Wed Apr 23 19:01:29 1997
+++ linux/kernel/fork.c	Mon May 12 10:35:44 1997
@@ -33,68 +33,177 @@
 unsigned long int total_forks=0;	/* Handle normal Linux uptimes. */
 int last_pid=0;
 
-static inline int find_empty_process(void)
+/* SLAB cache for mm_struct's. */
+kmem_cache_t *mm_cachep;
+
+struct task_struct *pidhash[PIDHASH_SZ];
+spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED;
+
+struct task_struct **tarray_freelist = NULL;
+spinlock_t taskslot_lock = SPIN_LOCK_UNLOCKED;
+
+/* UID task count cache, to prevent walking entire process list every
+ * single fork() operation.
+ */
+#define UIDHASH_SZ	(PIDHASH_SZ >> 2)
+
+static struct uid_taskcount {
+	struct uid_taskcount *next, **pprev;
+	unsigned short uid;
+	int task_count;
+} *uidhash[UIDHASH_SZ];
+static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
+
+kmem_cache_t *uid_cachep;
+
+#define uidhashfn(uid)	(((uid >> 8) ^ uid) & (UIDHASH_SZ - 1))
+
+static inline void uid_hash_insert(struct uid_taskcount *up, unsigned int hashent)
 {
-	int i;
+	spin_lock(&uidhash_lock);
+	if((up->next = uidhash[hashent]) != NULL)
+		uidhash[hashent]->pprev = &up->next;
+	up->pprev = &uidhash[hashent];
+	uidhash[hashent] = up;
+	spin_unlock(&uidhash_lock);
+}
 
-	if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) {
-		if (current->uid)
-			return -EAGAIN;
-	}
-	if (current->uid) {
-		long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur;
+static inline void uid_hash_remove(struct uid_taskcount *up)
+{
+	spin_lock(&uidhash_lock);
+	if(up->next)
+		up->next->pprev = up->pprev;
+	*up->pprev = up->next;
+	spin_unlock(&uidhash_lock);
+}
 
-		max_tasks--;	/* count the new process.. */
-		if (max_tasks < nr_tasks) {
-			struct task_struct *p;
-			read_lock(&tasklist_lock);
-			for_each_task (p) {
-				if (p->uid == current->uid)
-					if (--max_tasks < 0) {
-						read_unlock(&tasklist_lock);
-						return -EAGAIN;
-					}
-			}
-			read_unlock(&tasklist_lock);
+static inline struct uid_taskcount *uid_find(unsigned short uid, unsigned int hashent)
+{
+	struct uid_taskcount *up;
+
+	spin_lock(&uidhash_lock);
+	for(up = uidhash[hashent]; (up && up->uid != uid); up = up->next)
+		;
+	spin_unlock(&uidhash_lock);
+	return up;
+}
+
+int charge_uid(struct task_struct *p, int count)
+{
+	unsigned int hashent = uidhashfn(p->uid);
+	struct uid_taskcount *up = uid_find(p->uid, hashent);
+
+	if(up) {
+		int limit = p->rlim[RLIMIT_NPROC].rlim_cur;
+		int newcnt = up->task_count + count;
+
+		if(newcnt > limit)
+			return -EAGAIN;
+		else if(newcnt == 0) {
+			uid_hash_remove(up);
+			kmem_cache_free(uid_cachep, up);
+			return 0;
 		}
+	} else {
+		up = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
+		if(!up)
+			return -EAGAIN;
+		up->uid = p->uid;
+		up->task_count = 0;
+		uid_hash_insert(up, hashent);
 	}
-	for (i = 0 ; i < NR_TASKS ; i++) {
-		if (!task[i])
-			return i;
+	up->task_count += count;
+	return 0;
+}
+
+void uidcache_init(void)
+{
+	int i;
+
+	uid_cachep = kmem_cache_create("uid_cache", sizeof(struct uid_taskcount),
+				       sizeof(unsigned long) * 2,
+				       SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if(!uid_cachep)
+		panic("Cannot create uid taskcount SLAB cache\n");
+
+	for(i = 0; i < UIDHASH_SZ; i++)
+		uidhash[i] = 0;
+}
+
+static inline int find_empty_process(void)
+{
+	struct task_struct **tslot;
+
+	if(current->uid) {
+		int error;
+
+		if(nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT)
+			return -EAGAIN;
+		if((error = charge_uid(current, 1)) < 0)
+			return error;
 	}
+	tslot = get_free_taskslot();
+	if(tslot)
+		return tslot - &task[0];
 	return -EAGAIN;
 }
 
+/* Protects next_safe and last_pid. */
+static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
+
 static int get_pid(unsigned long flags)
 {
+	static int next_safe = PID_MAX;
 	struct task_struct *p;
 
 	if (flags & CLONE_PID)
 		return current->pid;
 
-	read_lock(&tasklist_lock);
-repeat:
-	if ((++last_pid) & 0xffff8000)
-		last_pid=1;
-	for_each_task (p) {
-		if (p->pid == last_pid ||
-		    p->pgrp == last_pid ||
-		    p->session == last_pid)
-			goto repeat;
+	spin_lock(&lastpid_lock);
+	if((++last_pid) & 0xffff8000) {
+		last_pid = 300;		/* Skip daemons etc. */
+		goto inside;
+	}
+	if(last_pid >= next_safe) {
+inside:
+		next_safe = PID_MAX;
+		read_lock(&tasklist_lock);
+	repeat:
+		for_each_task(p) {
+			if(p->pid == last_pid	||
+			   p->pgrp == last_pid	||
+			   p->session == last_pid) {
+				if(++last_pid >= next_safe) {
+					if(last_pid & 0xffff8000)
+						last_pid = 300;
+					next_safe = PID_MAX;
+					goto repeat;
+				}
+			}
+			if(p->pid > last_pid && next_safe > p->pid)
+				next_safe = p->pid;
+			if(p->pgrp > last_pid && next_safe > p->pgrp)
+				next_safe = p->pgrp;
+			if(p->session > last_pid && next_safe > p->session)
+				next_safe = p->session;
+		}
+		read_unlock(&tasklist_lock);
 	}
-	read_unlock(&tasklist_lock);
+	spin_unlock(&lastpid_lock);
 
 	return last_pid;
 }
 
 static inline int dup_mmap(struct mm_struct * mm)
 {
-	struct vm_area_struct * mpnt, **p, *tmp;
+	struct vm_area_struct * mpnt, *tmp, **pprev;
 
-	mm->mmap = NULL;
-	p = &mm->mmap;
+	mm->mmap = mm->mmap_cache = NULL;
 	flush_cache_mm(current->mm);
+	pprev = &mm->mmap;
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
+		struct inode *inode;
+
 		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 		if (!tmp) {
 			exit_mmap(mm);
@@ -105,12 +214,18 @@
 		tmp->vm_flags &= ~VM_LOCKED;
 		tmp->vm_mm = mm;
 		tmp->vm_next = NULL;
-		if (tmp->vm_inode) {
-			tmp->vm_inode->i_count++;
+		inode = tmp->vm_inode;
+		if (inode) {
+			inode->i_count++;
+			if (tmp->vm_flags & VM_DENYWRITE)
+				inode->i_writecount--;
+      
 			/* insert tmp into the share list, just after mpnt */
-			tmp->vm_next_share->vm_prev_share = tmp;
+			if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
+				mpnt->vm_next_share->vm_pprev_share =
+					&tmp->vm_next_share;
 			mpnt->vm_next_share = tmp;
-			tmp->vm_prev_share = mpnt;
+			tmp->vm_pprev_share = &mpnt->vm_next_share;
 		}
 		if (copy_page_range(mm, current->mm, tmp)) {
 			exit_mmap(mm);
@@ -119,18 +234,23 @@
 		}
 		if (tmp->vm_ops && tmp->vm_ops->open)
 			tmp->vm_ops->open(tmp);
-		*p = tmp;
-		p = &tmp->vm_next;
+
+		/* Ok, finally safe to link it in. */
+		if((tmp->vm_next = *pprev) != NULL)
+			(*pprev)->vm_pprev = &tmp->vm_next;
+		*pprev = tmp;
+		tmp->vm_pprev = pprev;
+
+		pprev = &tmp->vm_next;
 	}
 	flush_tlb_mm(current->mm);
-	build_mmap_avl(mm);
 	return 0;
 }
 
 static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
 	if (!(clone_flags & CLONE_VM)) {
-		struct mm_struct * mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL);
+		struct mm_struct * mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
 		if (!mm)
 			return -1;
 		*mm = *current->mm;
@@ -146,7 +266,7 @@
 		if (dup_mmap(mm)) {
 			free_page_tables(mm);
 free_mm:
-			kfree(mm);
+			kmem_cache_free(mm_cachep, mm);
 			return -1;
 		}
 		return 0;
@@ -232,20 +352,17 @@
 {
 	int nr;
 	int error = -ENOMEM;
-	unsigned long new_stack;
 	struct task_struct *p;
 
 	lock_kernel();
 	p = alloc_task_struct();
 	if (!p)
 		goto bad_fork;
-	new_stack = alloc_kernel_stack(p);
-	if (!new_stack)
-		goto bad_fork_free_p;
+
 	error = -EAGAIN;
 	nr = find_empty_process();
 	if (nr < 0)
-		goto bad_fork_free_stack;
+		goto bad_fork_free;
 
 	*p = *current;
 
@@ -256,8 +373,6 @@
 
 	p->did_exec = 0;
 	p->swappable = 0;
-	p->kernel_stack_page = new_stack;
-	*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
 	p->state = TASK_UNINTERRUPTIBLE;
 	p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV);
 	p->flags |= PF_FORKNOEXEC;
@@ -277,12 +392,15 @@
 	p->utime = p->stime = 0;
 	p->cutime = p->cstime = 0;
 #ifdef __SMP__
+	p->has_cpu = 0;
 	p->processor = NO_PROC_ID;
 #endif
 	p->lock_depth = 0;
 	p->start_time = jiffies;
-	task[nr] = p;
+	p->tarray_ptr = &task[nr];
+	*p->tarray_ptr = p;
 	SET_LINKS(p);
+	hash_pid(p);
 	nr_tasks++;
 
 	error = -ENOMEM;
@@ -330,16 +448,16 @@
 bad_fork_cleanup_files:
 	exit_files(p);
 bad_fork_cleanup:
+	charge_uid(current, -1);
 	if (p->exec_domain && p->exec_domain->module)
 		__MOD_DEC_USE_COUNT(p->exec_domain->module);
 	if (p->binfmt && p->binfmt->module)
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
-	task[nr] = NULL;
+	add_free_taskslot(p->tarray_ptr);
+	unhash_pid(p);
 	REMOVE_LINKS(p);
 	nr_tasks--;
-bad_fork_free_stack:
-	free_kernel_stack(new_stack);
-bad_fork_free_p:
+bad_fork_free:
 	free_task_struct(p);
 bad_fork:
 fork_out:
diff -u --recursive --new-file v2.1.36/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.36/linux/kernel/ksyms.c	Wed Apr 23 19:01:29 1997
+++ linux/kernel/ksyms.c	Mon May 12 10:35:44 1997
@@ -150,6 +150,7 @@
 EXPORT_SYMBOL(open_namei);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(close_fp);
+EXPORT_SYMBOL(insert_file_free);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
@@ -300,7 +301,6 @@
 EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(schedule);
-EXPORT_SYMBOL(current_set);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
diff -u --recursive --new-file v2.1.36/linux/kernel/panic.c linux/kernel/panic.c
--- v2.1.36/linux/kernel/panic.c	Fri Apr  4 08:52:26 1997
+++ linux/kernel/panic.c	Mon May 12 10:35:44 1997
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/reboot.h>
+#include <linux/init.h>
 
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void unblank_console(void);
@@ -22,7 +23,7 @@
 
 int panic_timeout = 0;
 
-void panic_setup(char *str, int *ints)
+__initfunc(void panic_setup(char *str, int *ints))
 {
 	if (ints[0] == 1)
 		panic_timeout = ints[1];
diff -u --recursive --new-file v2.1.36/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.36/linux/kernel/printk.c	Sun Apr 13 10:18:22 1997
+++ linux/kernel/printk.c	Mon May 12 10:35:44 1997
@@ -25,6 +25,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/console.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 
@@ -261,7 +262,7 @@
  * print any messages that were printed by the kernel before the
  * console driver was initialized.
  */
-void register_console(struct console * console)
+__initfunc(void register_console(struct console * console))
 {
 	int	i,j,len;
 	int	p = log_start;
diff -u --recursive --new-file v2.1.36/linux/kernel/resource.c linux/kernel/resource.c
--- v2.1.36/linux/kernel/resource.c	Mon Apr 14 16:28:26 1997
+++ linux/kernel/resource.c	Mon May 12 10:35:44 1997
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #define IOTABLE_SIZE 128
 
@@ -181,7 +182,7 @@
 #endif
 
 /* Called from init/main.c to reserve IO ports. */
-void reserve_setup(char *str, int *ints)
+__initfunc(void reserve_setup(char *str, int *ints))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.36/linux/kernel/sched.c	Wed Apr 23 19:01:29 1997
+++ linux/kernel/sched.c	Mon May 12 10:35:44 1997
@@ -32,6 +32,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -88,16 +89,6 @@
 
 extern void mem_use(void);
 
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
-static struct vm_area_struct init_mmap = INIT_MMAP;
-static struct fs_struct init_fs = INIT_FS;
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
-
-struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
 unsigned long volatile jiffies=0;
 
 /*
@@ -105,7 +96,6 @@
  *	via the SMP irq return path.
  */
  
-struct task_struct *current_set[NR_CPUS] = {&init_task, };
 struct task_struct *last_task_used_math = NULL;
 
 struct task_struct * task[NR_TASKS] = {&init_task, };
@@ -114,12 +104,6 @@
 
 static inline void add_to_runqueue(struct task_struct * p)
 {
-#if 1	/* sanity tests */
-	if (p->next_run || p->prev_run) {
-		printk("task already on run-queue\n");
-		return;
-	}
-#endif
 	if (p->counter > current->counter + 3)
 		need_resched = 1;
 	nr_running++;
@@ -133,20 +117,6 @@
 	struct task_struct *next = p->next_run;
 	struct task_struct *prev = p->prev_run;
 
-#if 1	/* sanity tests */
-	if (!next || !prev) {
-		printk("task not on run-queue\n");
-		return;
-	}
-#endif
-	if (!p->pid) {
-		static int nr = 0;
-		if (nr < 5) {
-			nr++;
-			printk("idle task may not sleep\n");
-		}
-		return;
-	}
 	nr_running--;
 	next->prev_run = prev;
 	prev->next_run = next;
@@ -250,7 +220,7 @@
 #ifdef __SMP__
 		/* Give a largish advantage to the same processor...   */
 		/* (this is equivalent to penalizing other processors) */
-		if (p->last_processor == this_cpu)
+		if (p->processor == this_cpu)
 			weight += PROC_CHANGE_PENALTY;
 #endif
 
@@ -262,10 +232,127 @@
 	return weight;
 }
 
+/*
+ * Event timer code
+ */
+#define TVN_BITS 6
+#define TVR_BITS 8
+#define TVN_SIZE (1 << TVN_BITS)
+#define TVR_SIZE (1 << TVR_BITS)
+#define TVN_MASK (TVN_SIZE - 1)
+#define TVR_MASK (TVR_SIZE - 1)
+
+struct timer_vec {
+        int index;
+        struct timer_list *vec[TVN_SIZE];
+};
+
+struct timer_vec_root {
+        int index;
+        struct timer_list *vec[TVR_SIZE];
+};
+
+static struct timer_vec tv5 = { 0 };
+static struct timer_vec tv4 = { 0 };
+static struct timer_vec tv3 = { 0 };
+static struct timer_vec tv2 = { 0 };
+static struct timer_vec_root tv1 = { 0 };
+
+static struct timer_vec * const tvecs[] = {
+	(struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5
+};
+
+#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
+
+static unsigned long timer_jiffies = 0;
+
+static inline void insert_timer(struct timer_list *timer,
+				struct timer_list **vec, int idx)
+{
+	if ((timer->next = vec[idx]))
+		vec[idx]->prev = timer;
+	vec[idx] = timer;
+	timer->prev = (struct timer_list *)&vec[idx];
+}
+
+static inline void internal_add_timer(struct timer_list *timer)
+{
+	/*
+	 * must be cli-ed when calling this
+	 */
+	unsigned long expires = timer->expires;
+	unsigned long idx = expires - timer_jiffies;
+
+	if (idx < TVR_SIZE) {
+		int i = expires & TVR_MASK;
+		insert_timer(timer, tv1.vec, i);
+	} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
+		int i = (expires >> TVR_BITS) & TVN_MASK;
+		insert_timer(timer, tv2.vec, i);
+	} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
+		int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
+		insert_timer(timer, tv3.vec, i);
+	} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
+		int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
+		insert_timer(timer, tv4.vec, i);
+	} else if (expires < timer_jiffies) {
+		/* can happen if you add a timer with expires == jiffies,
+		 * or you set a timer to go off in the past
+		 */
+		insert_timer(timer, tv1.vec, tv1.index);
+	} else if (idx < 0xffffffffUL) {
+		int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
+		insert_timer(timer, tv5.vec, i);
+	} else {
+		/* Can only get here on architectures with 64-bit jiffies */
+		timer->next = timer->prev = timer;
+	}
+}
+
+static spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
+
+void add_timer(struct timer_list *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&timerlist_lock, flags);
+	internal_add_timer(timer);
+	spin_unlock_irqrestore(&timerlist_lock, flags);
+}
+
+static inline int detach_timer(struct timer_list *timer)
+{
+	int ret = 0;
+	struct timer_list *next, *prev;
+	next = timer->next;
+	prev = timer->prev;
+	if (next) {
+		next->prev = prev;
+	}
+	if (prev) {
+		ret = 1;
+		prev->next = next;
+	}
+	return ret;
+}
+
+
+int del_timer(struct timer_list * timer)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&timerlist_lock, flags);
+	ret = detach_timer(timer);
+	timer->next = timer->prev = 0;
+	spin_unlock_irqrestore(&timerlist_lock, flags);
+	return ret;
+}
+
 #ifdef __SMP__
 
 #define idle_task (task[cpu_number_map[this_cpu]])
-#define can_schedule(p)	((p)->processor == NO_PROC_ID)
+#define can_schedule(p)	(!(p)->has_cpu)
 
 #else
 
@@ -292,12 +379,10 @@
 	int this_cpu;
 
 	need_resched = 0;
-	this_cpu = smp_processor_id();
-	if (local_irq_count[this_cpu]) {
-		printk("Scheduling in interrupt\n");
-		*(char *)0 = 0;
-	}
 	prev = current;
+	this_cpu = smp_processor_id();
+	if (local_irq_count[this_cpu])
+		goto scheduling_in_interrupt;
 	release_kernel_lock(prev, this_cpu, lock_depth);
 	if (bh_active & bh_mask)
 		do_bottom_half();
@@ -307,16 +392,8 @@
 
 	/* move an exhausted RR process to be last.. */
 	if (!prev->counter && prev->policy == SCHED_RR) {
-		if (prev->pid) {
-			prev->counter = prev->priority;
-			move_last_runqueue(prev);
-		} else {
-			static int count = 5;
-			if (count) {
-				count--;
-				printk("Moving pid 0 last\n");
-			}
-		}
+		prev->counter = prev->priority;
+		move_last_runqueue(prev);
 	}
 	timeout = 0;
 	switch (prev->state) {
@@ -349,7 +426,7 @@
 		 */
 		spin_unlock_irq(&runqueue_lock);
 #ifdef __SMP__
-		prev->processor = NO_PROC_ID;
+		prev->has_cpu = 0;
 #endif
 	
 /*
@@ -381,8 +458,10 @@
 		}
 	}
 
+#ifdef __SMP__
+	next->has_cpu = 1;
 	next->processor = this_cpu;
-	next->last_processor = this_cpu;
+#endif
 
 	if (prev != next) {
 		struct timer_list timer;
@@ -404,6 +483,11 @@
 	spin_unlock(&scheduler_lock);
 
 	reacquire_kernel_lock(prev, smp_processor_id(), lock_depth);
+	return;
+
+scheduling_in_interrupt:
+	printk("Scheduling in interrupt\n");
+	*(int *)0 = 0;
 }
 
 #ifndef __alpha__
@@ -421,67 +505,53 @@
 
 #endif
 
-spinlock_t waitqueue_lock;
+rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED;
 
 /*
  * wake_up doesn't wake up stopped processes - they have to be awakened
  * with signals or similar.
+ *
+ * Note that we only need a read lock for the wait queue (and thus do not
+ * have to protect against interrupts), as the actual removal from the
+ * queue is handled by the process itself.
  */
 void wake_up(struct wait_queue **q)
 {
-	unsigned long flags;
 	struct wait_queue *next;
-	struct wait_queue *head;
 
-	spin_lock_irqsave(&waitqueue_lock, flags);
+	read_lock(&waitqueue_lock);
 	if (q && (next = *q)) {
+		struct wait_queue *head;
+
 		head = WAIT_QUEUE_HEAD(q);
 		while (next != head) {
 			struct task_struct *p = next->task;
 			next = next->next;
-			if (p != NULL) {
-				if ((p->state == TASK_UNINTERRUPTIBLE) ||
-				    (p->state == TASK_INTERRUPTIBLE))
-					wake_up_process(p);
-			}
-			if (next)
-				continue;
-			printk("wait_queue is bad (eip = %p)\n",
-				__builtin_return_address(0));
-			printk("        q = %p\n",q);
-			printk("       *q = %p\n",*q);
-			break;
+			if ((p->state == TASK_UNINTERRUPTIBLE) ||
+			    (p->state == TASK_INTERRUPTIBLE))
+				wake_up_process(p);
 		}
 	}
-	spin_unlock_irqrestore(&waitqueue_lock, flags);
+	read_unlock(&waitqueue_lock);
 }
 
 void wake_up_interruptible(struct wait_queue **q)
 {
-	unsigned long flags;
 	struct wait_queue *next;
-	struct wait_queue *head;
 
-	spin_lock_irqsave(&waitqueue_lock, flags);
+	read_lock(&waitqueue_lock);
 	if (q && (next = *q)) {
+		struct wait_queue *head;
+
 		head = WAIT_QUEUE_HEAD(q);
 		while (next != head) {
 			struct task_struct *p = next->task;
 			next = next->next;
-			if (p != NULL) {
-				if (p->state == TASK_INTERRUPTIBLE)
-					wake_up_process(p);
-			}
-			if (next)
-				continue;
-			printk("wait_queue is bad (eip = %p)\n",
-				__builtin_return_address(0));
-			printk("        q = %p\n",q);
-			printk("       *q = %p\n",*q);
-			break;
+			if (p->state == TASK_INTERRUPTIBLE)
+				wake_up_process(p);
 		}
 	}
-	spin_unlock_irqrestore(&waitqueue_lock, flags);
+	read_unlock(&waitqueue_lock);
 }
 
 /*
@@ -600,17 +670,14 @@
 
 	if (!p)
 		return;
-	if (current == task[0])
-		panic("task[0] trying to sleep");
 	current->state = state;
-	spin_lock_irqsave(&waitqueue_lock, flags);
+	write_lock_irqsave(&waitqueue_lock, flags);
 	__add_wait_queue(p, &wait);
-	spin_unlock(&waitqueue_lock);
-	sti();
+	write_unlock(&waitqueue_lock);
 	schedule();
-	spin_lock_irq(&waitqueue_lock);
+	write_lock_irq(&waitqueue_lock);
 	__remove_wait_queue(p, &wait);
-	spin_unlock_irqrestore(&waitqueue_lock, flags);
+	write_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
 void interruptible_sleep_on(struct wait_queue **p)
@@ -623,133 +690,6 @@
 	__sleep_on(p,TASK_UNINTERRUPTIBLE);
 }
 
-
-#define TVN_BITS 6
-#define TVR_BITS 8
-#define TVN_SIZE (1 << TVN_BITS)
-#define TVR_SIZE (1 << TVR_BITS)
-#define TVN_MASK (TVN_SIZE - 1)
-#define TVR_MASK (TVR_SIZE - 1)
-
-#define SLOW_BUT_DEBUGGING_TIMERS 0
-
-struct timer_vec {
-        int index;
-        struct timer_list *vec[TVN_SIZE];
-};
-
-struct timer_vec_root {
-        int index;
-        struct timer_list *vec[TVR_SIZE];
-};
-
-static struct timer_vec tv5 = { 0 };
-static struct timer_vec tv4 = { 0 };
-static struct timer_vec tv3 = { 0 };
-static struct timer_vec tv2 = { 0 };
-static struct timer_vec_root tv1 = { 0 };
-
-static struct timer_vec * const tvecs[] = {
-	(struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5
-};
-
-#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
-
-static unsigned long timer_jiffies = 0;
-
-static inline void insert_timer(struct timer_list *timer,
-				struct timer_list **vec, int idx)
-{
-	if ((timer->next = vec[idx]))
-		vec[idx]->prev = timer;
-	vec[idx] = timer;
-	timer->prev = (struct timer_list *)&vec[idx];
-}
-
-static inline void internal_add_timer(struct timer_list *timer)
-{
-	/*
-	 * must be cli-ed when calling this
-	 */
-	unsigned long expires = timer->expires;
-	unsigned long idx = expires - timer_jiffies;
-
-	if (idx < TVR_SIZE) {
-		int i = expires & TVR_MASK;
-		insert_timer(timer, tv1.vec, i);
-	} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
-		int i = (expires >> TVR_BITS) & TVN_MASK;
-		insert_timer(timer, tv2.vec, i);
-	} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
-		int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
-		insert_timer(timer, tv3.vec, i);
-	} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
-		int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
-		insert_timer(timer, tv4.vec, i);
-	} else if (expires < timer_jiffies) {
-		/* can happen if you add a timer with expires == jiffies,
-		 * or you set a timer to go off in the past
-		 */
-		insert_timer(timer, tv1.vec, tv1.index);
-	} else if (idx < 0xffffffffUL) {
-		int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
-		insert_timer(timer, tv5.vec, i);
-	} else {
-		/* Can only get here on architectures with 64-bit jiffies */
-		timer->next = timer->prev = timer;
-	}
-}
-
-static spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
-
-void add_timer(struct timer_list *timer)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&timerlist_lock, flags);
-#if SLOW_BUT_DEBUGGING_TIMERS
-        if (timer->next || timer->prev) {
-                printk("add_timer() called with non-zero list from %p\n",
-		       __builtin_return_address(0));
-		goto out;
-        }
-#endif
-	internal_add_timer(timer);
-#if SLOW_BUT_DEBUGGING_TIMERS
-out:
-#endif
-	spin_unlock_irqrestore(&timerlist_lock, flags);
-}
-
-static inline int detach_timer(struct timer_list *timer)
-{
-	int ret = 0;
-	struct timer_list *next, *prev;
-	next = timer->next;
-	prev = timer->prev;
-	if (next) {
-		next->prev = prev;
-	}
-	if (prev) {
-		ret = 1;
-		prev->next = next;
-	}
-	return ret;
-}
-
-
-int del_timer(struct timer_list * timer)
-{
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&timerlist_lock, flags);
-	ret = detach_timer(timer);
-	timer->next = timer->prev = 0;
-	spin_unlock_irqrestore(&timerlist_lock, flags);
-	return ret;
-}
-
 static inline void cascade_timers(struct timer_vec *tv)
 {
         /* cascade all the timers from tv up one level */
@@ -841,17 +781,18 @@
  */
 static unsigned long count_active_tasks(void)
 {
-	struct task_struct **p;
+	struct task_struct *p;
 	unsigned long nr = 0;
 
-	for(p = &LAST_TASK; p > &FIRST_TASK; --p)
-		if (*p && ((*p)->state == TASK_RUNNING ||
-			   (*p)->state == TASK_UNINTERRUPTIBLE ||
-			   (*p)->state == TASK_SWAPPING))
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (p->pid &&
+		    (p->state == TASK_RUNNING ||
+		     p->state == TASK_UNINTERRUPTIBLE ||
+		     p->state == TASK_SWAPPING))
 			nr += FIXED_1;
-#ifdef __SMP__
-	nr-=(smp_num_cpus-1)*FIXED_1;
-#endif			
+	}
+	read_unlock(&tasklist_lock);
 	return nr;
 }
 
@@ -1338,22 +1279,12 @@
 
 #endif
 
-static struct task_struct *find_process_by_pid(pid_t pid)
+static inline struct task_struct *find_process_by_pid(pid_t pid)
 {
-	struct task_struct *p;
-
-	p = current;
-	if (pid) {
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid == pid)
-				goto found;
-		}
-		p = NULL;
-found:
-		read_unlock(&tasklist_lock);
-	}
-	return p;
+	if (pid)
+		return find_task_by_pid(pid);
+	else
+		return current;
 }
 
 static int setscheduler(pid_t pid, int policy, 
@@ -1566,7 +1497,7 @@
 
 static void show_task(int nr,struct task_struct * p)
 {
-	unsigned long free;
+	unsigned long free = 0;
 	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
 	printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
@@ -1585,10 +1516,12 @@
 	else
 		printk(" %016lx ", thread_saved_pc(&p->tss));
 #endif
+#if 0
 	for (free = 1; free < PAGE_SIZE/sizeof(long) ; free++) {
 		if (((unsigned long *)p->kernel_stack_page)[free])
 			break;
 	}
+#endif
 	printk("%5lu %5d %6d ", free*sizeof(long), p->pid, p->p_pptr->pid);
 	if (p->p_cptr)
 		printk("%5d ", p->p_cptr->pid);
@@ -1606,7 +1539,7 @@
 
 void show_state(void)
 {
-	int i;
+	struct task_struct *p;
 
 #if ((~0UL) == 0xffffffff)
 	printk("\n"
@@ -1617,25 +1550,30 @@
 	       "                                 free                        sibling\n");
 	printk("  task                 PC        stack   pid father child younger older\n");
 #endif
-	for (i=0 ; i<NR_TASKS ; i++)
-		if (task[i])
-			show_task(i,task[i]);
+	read_lock(&tasklist_lock);
+	for_each_task(p)
+		show_task((p->tarray_ptr - &task[0]),p);
+	read_unlock(&tasklist_lock);
 }
 
-void sched_init(void)
+__initfunc(void sched_init(void))
 {
 	/*
 	 *	We have to do a little magic to get the first
 	 *	process right in SMP mode.
 	 */
-	int cpu=smp_processor_id();
-#ifndef __SMP__
-	current_set[cpu]=&init_task;
-#else
+	int cpu=hard_smp_processor_id();
+	int nr = NR_TASKS;
+
 	init_task.processor=cpu;
-	for(cpu = 0; cpu < NR_CPUS; cpu++)
-		current_set[cpu] = &init_task;
-#endif
+
+	/* Init task array free list and pidhash table. */
+	while(--nr > 0)
+		add_free_taskslot(&task[nr]);
+
+	for(nr = 0; nr < PIDHASH_SZ; nr++)
+		pidhash[nr] = NULL;
+
 	init_bh(TIMER_BH, timer_bh);
 	init_bh(TQUEUE_BH, tqueue_bh);
 	init_bh(IMMEDIATE_BH, immediate_bh);
diff -u --recursive --new-file v2.1.36/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.1.36/linux/kernel/softirq.c	Mon Apr 14 16:28:26 1997
+++ linux/kernel/softirq.c	Tue May 13 21:40:00 1997
@@ -62,13 +62,14 @@
 
 asmlinkage void do_bottom_half(void)
 {
-	int cpu = smp_processor_id();
+	if (softirq_trylock()) {
+		int cpu = smp_processor_id();
 
-	if (hardirq_trylock(cpu)) {
-		if (softirq_trylock()) {
+		if (hardirq_trylock(cpu)) {
+			__sti();
 			run_bottom_halves();
-			softirq_endlock();
+			hardirq_endlock(cpu);
 		}
-		hardirq_endlock(cpu);
+		softirq_endlock();
 	}
 }
diff -u --recursive --new-file v2.1.36/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.36/linux/kernel/sys.c	Wed Apr 23 19:01:29 1997
+++ linux/kernel/sys.c	Mon May 12 10:35:44 1997
@@ -523,16 +523,15 @@
  */
 asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
 {
-	int old_ruid;
-	int old_euid;
+	int old_ruid, old_euid, new_ruid;
 
-	old_ruid = current->uid;
+	new_ruid = old_ruid = current->uid;
 	old_euid = current->euid;
 	if (ruid != (uid_t) -1) {
 		if ((old_ruid == ruid) || 
 		    (current->euid==ruid) ||
 		    suser())
-			current->uid = ruid;
+			new_ruid = ruid;
 		else
 			return -EPERM;
 	}
@@ -542,10 +541,8 @@
 		    (current->suid == euid) ||
 		    suser())
 			current->fsuid = current->euid = euid;
-		else {
-			current->uid = old_ruid;
+		else
 			return -EPERM;
-		}
 	}
 	if (ruid != (uid_t) -1 ||
 	    (euid != (uid_t) -1 && euid != old_ruid))
@@ -553,6 +550,18 @@
 	current->fsuid = current->euid;
 	if (current->euid != old_euid)
 		current->dumpable = 0;
+
+	if(new_ruid != old_ruid) {
+		/* What if a process setreuid()'s and this brings the
+		 * new uid over his NPROC rlimit?  We can check this now
+		 * cheaply with the new uid cache, so if it matters
+		 * we should be checking for it.  -DaveM
+		 */
+		charge_uid(current, -1);
+		current->uid = new_ruid;
+		if(new_ruid)
+			charge_uid(current, 1);
+	}
 	return 0;
 }
 
@@ -570,9 +579,11 @@
 asmlinkage int sys_setuid(uid_t uid)
 {
 	int old_euid = current->euid;
+	int old_ruid, new_ruid;
 
+	old_ruid = new_ruid = current->uid;
 	if (suser())
-		current->uid = current->euid = current->suid = current->fsuid = uid;
+		new_ruid = current->euid = current->suid = current->fsuid = uid;
 	else if ((uid == current->uid) || (uid == current->suid))
 		current->fsuid = current->euid = uid;
 	else
@@ -580,6 +591,14 @@
 
 	if (current->euid != old_euid)
 		current->dumpable = 0;
+
+	if(new_ruid != old_ruid) {
+		/* See comment above about NPROC rlimit issues... */
+		charge_uid(current, -1);
+		current->uid = new_ruid;
+		if(new_ruid)
+			charge_uid(current, 1);
+	}
 	return 0;
 }
 
@@ -605,8 +624,13 @@
 	if ((suid != (uid_t) -1) && (suid != current->uid) &&
 	    (suid != current->euid) && (suid != current->suid))
 		return -EPERM;
-	if (ruid != (uid_t) -1)
+	if (ruid != (uid_t) -1) {
+		/* See above commentary about NPROC rlimit issues here. */
+		charge_uid(current, -1);
 		current->uid = ruid;
+		if(ruid)
+			charge_uid(current, 1);
+	}
 	if (euid != (uid_t) -1)
 		current->euid = euid;
 	if (suid != (uid_t) -1)
@@ -709,22 +733,13 @@
 	if (pgid < 0)
 		return -EINVAL;
 
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (p->pid == pid) {
-			/* NOTE: I haven't dropped tasklist_lock, this is
-			 *       on purpose. -DaveM
-			 */
-			goto found_task;
-		}
-	}
-	read_unlock(&tasklist_lock);
-	return -ESRCH;
+	if((p = find_task_by_pid(pid)) == NULL)
+		return -ESRCH;
 
-found_task:
 	/* From this point forward we keep holding onto the tasklist lock
 	 * so that our parent does not change from under us. -DaveM
 	 */
+	read_lock(&tasklist_lock);
 	err = -ESRCH;
 	if (p->p_pptr == current || p->p_opptr == current) {
 		err = -EPERM;
@@ -762,18 +777,12 @@
 	if (!pid) {
 		return current->pgrp;
 	} else {
-		struct task_struct *p;
-		int ret = -ESRCH;
+		struct task_struct *p = find_task_by_pid(pid);
 
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid == pid) {
-				ret = p->pgrp;
-				break;
-			}
-		}
-		read_unlock(&tasklist_lock);
-		return ret;
+		if(p)
+			return p->pgrp;
+		else
+			return -ESRCH;
 	}
 }
 
@@ -785,25 +794,16 @@
 
 asmlinkage int sys_getsid(pid_t pid)
 {
-	struct task_struct * p;
-	int ret;
-
-	/* SMP: The 'self' case requires no lock */
 	if (!pid) {
-		ret = current->session;
+		return current->session;
 	} else {
-		ret = -ESRCH;
+		struct task_struct *p = find_task_by_pid(pid);
 
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid == pid) {
-				ret = p->session;
-				break;
-			}
-		}
-		read_unlock(&tasklist_lock);
+		if(p)
+			return p->session;
+		else
+			return -ESRCH;
 	}
-	return ret;
 }
 
 asmlinkage int sys_setsid(void)
diff -u --recursive --new-file v2.1.36/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.36/linux/kernel/sysctl.c	Sun Apr 13 10:18:22 1997
+++ linux/kernel/sysctl.c	Mon May 12 10:35:44 1997
@@ -24,6 +24,7 @@
 #include <linux/swapctl.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -210,7 +211,7 @@
 };  
 
 
-void sysctl_init(void)
+__initfunc(void sysctl_init(void))
 {
 #ifdef CONFIG_PROC_FS
 	register_proc_table(root_table, &proc_sys_root);
diff -u --recursive --new-file v2.1.36/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.36/linux/mm/filemap.c	Mon Apr 14 16:28:26 1997
+++ linux/mm/filemap.c	Mon May 12 10:35:44 1997
@@ -171,7 +171,7 @@
 		switch (atomic_read(&page->count)) {
 			case 1:
 				/* If it has been referenced recently, don't free it */
-				if (clear_bit(PG_referenced, &page->flags))
+				if (test_and_clear_bit(PG_referenced, &page->flags))
 					break;
 
 				/* is it a page cache page? */
@@ -1340,7 +1340,7 @@
 		}
 
 lockit:
-		while (set_bit(PG_locked, &page->flags))
+		while (test_and_set_bit(PG_locked, &page->flags))
 			wait_on_page(page);
 
 		/*
diff -u --recursive --new-file v2.1.36/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v2.1.36/linux/mm/kmalloc.c	Mon Apr 14 16:28:27 1997
+++ linux/mm/kmalloc.c	Mon May 12 17:39:50 1997
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/dma.h>
@@ -201,7 +202,7 @@
 	free_pages((unsigned long) page, order);
 }
 
-long kmalloc_init(long start_mem, long end_mem)
+__initfunc(long kmalloc_init(long start_mem, long end_mem))
 {
 	int order;
 
@@ -223,6 +224,7 @@
 	return start_mem;
 }
 
+static spinlock_t kmalloc_lock;
 
 /*
  * Ugh, this is ugly, but we want the default case to run
@@ -276,8 +278,7 @@
 		}
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&kmalloc_lock, flags);
 	page = *pg;
 	if (!page)
 		goto no_bucket_page;
@@ -291,7 +292,7 @@
 	page->nfree--;
 	if (!page->nfree)
 		*pg = page->next;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&kmalloc_lock, flags);
 	bucket->nmallocs++;
 	bucket->nbytesmalloced += size;
 	p->bh_flags = type;	/* As of now this block is officially in use */
@@ -307,9 +308,9 @@
 	 * If we didn't find a page already allocated for this
 	 * bucket size, we need to get one..
 	 *
-	 * This can be done with ints on: it is private to this invocation
+	 * This can be done without locks: it is private to this invocation
 	 */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&kmalloc_lock, flags);
 
 	{
 		int i, sz;
@@ -345,7 +346,7 @@
 	 * Now we're going to muck with the "global" freelist
 	 * for this size: this should be uninterruptible
 	 */
-	cli();
+	spin_lock_irq(&kmalloc_lock);
 	page->next = *pg;
 	*pg = page;
 	goto found_it;
@@ -371,7 +372,7 @@
 	}
 
 not_free_on_freelist:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&kmalloc_lock, flags);
 	printk("Problem: block on freelist at %08lx isn't free.\n", (long) p);
 	return NULL;
 }
@@ -408,8 +409,7 @@
 #ifdef SADISTIC_KMALLOC
 	memset(ptr+1, 0x0e, ptr->bh_length);
 #endif
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&kmalloc_lock, flags);
 
 	bucket->nfrees++;
 	bucket->nbytesmalloced -= ptr->bh_length;
@@ -438,7 +438,7 @@
 		bucket->npages--;
 		free_kmalloc_pages(page, bucket->gfporder, dma);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&kmalloc_lock, flags);
 null_kfree:
 	return;
 
@@ -449,5 +449,5 @@
 
 not_on_freelist:
 	printk("Ooops. page %p doesn't show on freelist.\n", page);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&kmalloc_lock, flags);
 }
diff -u --recursive --new-file v2.1.36/linux/mm/memory.c linux/mm/memory.c
--- v2.1.36/linux/mm/memory.c	Mon Apr 14 16:28:27 1997
+++ linux/mm/memory.c	Mon May 12 17:39:50 1997
@@ -589,7 +589,7 @@
  * change only once the write actually happens. This avoids a few races,
  * and potentially makes it more efficient.
  */
-void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
 	pgd_t *page_dir;
@@ -785,7 +785,7 @@
  * As this is called only for pages that do not currently exist, we
  * do not need to flush old virtual caches or the TLB.
  */
-void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
 	pgd_t * pgd;
diff -u --recursive --new-file v2.1.36/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.36/linux/mm/mmap.c	Thu Feb 27 10:57:31 1997
+++ linux/mm/mmap.c	Mon May 12 10:35:44 1997
@@ -16,13 +16,13 @@
 #include <linux/swap.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 
-/*
- * description of effects of mapping type and prot in current implementation.
+/* description of effects of mapping type and prot in current implementation.
  * this is due to the limited x86 page protection hardware.  The expected
  * behavior is in parens:
  *
@@ -37,7 +37,6 @@
  *		x: (no) no	x: (no) yes	x: (no) yes	x: (yes) yes
  *
  */
-
 pgprot_t protection_map[16] = {
 	__P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
 	__S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
@@ -48,20 +47,18 @@
 
 int sysctl_overcommit_memory;
 
-/*
- * Check that a process has enough memory to allocate a
+/* Check that a process has enough memory to allocate a
  * new virtual mapping.
  */
 static inline int vm_enough_memory(long pages)
 {
-	/*
-	 * stupid algorithm to decide if we have enough memory: while
+	/* Stupid algorithm to decide if we have enough memory: while
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
 	 */
 	long freepages;
 	
-        /* sometimes we want to use more memory than we have. */
+        /* Sometimes we want to use more memory than we have. */
 	if (sysctl_overcommit_memory)
 	    return 1;
 
@@ -74,6 +71,20 @@
 	return freepages > pages;
 }
 
+/* Remove one vm structure from the inode's i_mmap ring. */
+static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
+{
+	struct inode * inode = vma->vm_inode;
+
+	if (inode) {
+		if (vma->vm_flags & VM_DENYWRITE)
+			inode->i_writecount++;
+		if(vma->vm_next_share)
+			vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
+		*vma->vm_pprev_share = vma->vm_next_share;
+	}
+}
+
 asmlinkage unsigned long sys_brk(unsigned long brk)
 {
 	unsigned long rlim, retval;
@@ -91,17 +102,14 @@
 		goto out;
 	}
 
-	/*
-	 * Always allow shrinking brk
-	 */
+	/* Always allow shrinking brk. */
 	if (brk <= mm->brk) {
 		retval = mm->brk = brk;
 		do_munmap(newbrk, oldbrk-newbrk);
 		goto out;
 	}
-	/*
-	 * Check against rlimit and stack..
-	 */
+
+	/* Check against rlimit and stack.. */
 	retval = mm->brk;
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 	if (rlim >= RLIM_INFINITY)
@@ -109,21 +117,15 @@
 	if (brk - mm->end_code > rlim)
 		goto out;
 
-	/*
-	 * Check against existing mmap mappings.
-	 */
+	/* Check against existing mmap mappings. */
 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
 		goto out;
 
-	/*
-	 * Check if we have enough memory..
-	 */
+	/* Check if we have enough memory.. */
 	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
 		goto out;
 
-	/*
-	 * Ok, looks good - let it rip.
-	 */
+	/* Ok, looks good - let it rip. */
 	if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
 		   PROT_READ|PROT_WRITE|PROT_EXEC,
 		   MAP_FIXED|MAP_PRIVATE, 0) == oldbrk)
@@ -134,8 +136,7 @@
 	return retval;
 }
 
-/*
- * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
+/* Combine the mmap "prot" and "flags" argument into one "vm_flags" used
  * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
  * into "VM_xxx".
  */
@@ -162,6 +163,7 @@
 {
 	struct mm_struct * mm = current->mm;
 	struct vm_area_struct * vma;
+	int correct_wcount = 0;
 
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return addr;
@@ -181,20 +183,17 @@
 			return -EAGAIN;
 	}
 
-	/*
-	 * do simple checking here so the lower-level routines won't have
+	/* Do simple checking here so the lower-level routines won't have
 	 * to. we assume access permissions have been handled by the open
 	 * of the memory object, so we don't do any here.
 	 */
-
 	if (file != NULL) {
 		switch (flags & MAP_TYPE) {
 		case MAP_SHARED:
 			if ((prot & PROT_WRITE) && !(file->f_mode & 2))
 				return -EACCES;
-			/*
-			 * make sure there are no mandatory locks on the file.
-			 */
+
+			/* make sure there are no mandatory locks on the file. */
 			if (locks_verify_locked(file->f_inode))
 				return -EAGAIN;
 			/* fall through */
@@ -206,18 +205,12 @@
 		default:
 			return -EINVAL;
 		}
-		if (flags & MAP_DENYWRITE) {
-			if (file->f_inode->i_writecount > 0)
-				return -ETXTBSY;
-		}
 	} else if ((flags & MAP_TYPE) != MAP_PRIVATE)
 		return -EINVAL;
 
-	/*
-	 * obtain the address to map to. we verify (or select) it and ensure
+	/* Obtain the address to map to. we verify (or select) it and ensure
 	 * that it represents a valid section of the address space.
 	 */
-
 	if (flags & MAP_FIXED) {
 		if (addr & ~PAGE_MASK)
 			return -EINVAL;
@@ -227,8 +220,7 @@
 			return -ENOMEM;
 	}
 
-	/*
-	 * determine the object being mapped and call the appropriate
+	/* Determine the object being mapped and call the appropriate
 	 * specific mapper. the address has already been validated, but
 	 * not unmapped, but the maps are removed from the list.
 	 */
@@ -249,8 +241,8 @@
 			vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 		if (flags & MAP_SHARED) {
 			vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
-			/*
-			 * This looks strange, but when we don't have the file open
+
+			/* This looks strange, but when we don't have the file open
 			 * for writing, we can demote the shared mapping to a simpler
 			 * private mapping. That also takes care of a security hole
 			 * with ptrace() writing to a shared mapping without write
@@ -289,9 +281,26 @@
 	}
 
 	if (file) {
-		int error = file->f_op->mmap(file->f_inode, file, vma);
+		int error = 0;
+		if (vma->vm_flags & VM_DENYWRITE) {
+			if (file->f_inode->i_writecount > 0)
+				error = -ETXTBSY;
+			else {
+	        		/* f_op->mmap might possibly sleep
+				 * (generic_file_mmap doesn't, but other code
+				 * might). In any case, this takes care of any
+				 * race that this might cause.
+				 */
+				file->f_inode->i_writecount--;
+				correct_wcount = 1;
+			}
+		}
+		if (!error)
+			error = file->f_op->mmap(file->f_inode, file, vma);
 	
 		if (error) {
+			if (correct_wcount)
+				file->f_inode->i_writecount++;
 			kmem_cache_free(vm_area_cachep, vma);
 			return error;
 		}
@@ -299,6 +308,8 @@
 
 	flags = vma->vm_flags;
 	insert_vm_struct(mm, vma);
+	if (correct_wcount)
+		file->f_inode->i_writecount++;
 	merge_segments(mm, vma->vm_start, vma->vm_end);
 
 	/* merge_segments might have merged our vma, so we can't use it any more */
@@ -317,8 +328,7 @@
 	return addr;
 }
 
-/*
- * Get an address range which is currently unmapped.
+/* Get an address range which is currently unmapped.
  * For mmap() without MAP_FIXED and shmat() with addr=0.
  * Return value 0 means ENOMEM.
  */
@@ -342,376 +352,7 @@
 	}
 }
 
-/*
- * Searching a VMA in the linear list task->mm->mmap is horribly slow.
- * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
- * from O(n) to O(log n), where n is the number of VMAs of the task
- * (typically around 6, but may reach 3000 in some cases).
- * Written by Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>.
- */
-
-/* We keep the list and tree sorted by address. */
-#define vm_avl_key	vm_end
-#define vm_avl_key_t	unsigned long	/* typeof(vma->avl_key) */
-
-/*
- * task->mm->mmap_avl is the AVL tree corresponding to task->mm->mmap
- * or, more exactly, its root.
- * A vm_area_struct has the following fields:
- *   vm_avl_left     left son of a tree node
- *   vm_avl_right    right son of a tree node
- *   vm_avl_height   1+max(heightof(left),heightof(right))
- * The empty tree is represented as NULL.
- */
-
-/* Since the trees are balanced, their height will never be large. */
-#define avl_maxheight	41	/* why this? a small exercise */
-#define heightof(tree)	((tree) == avl_empty ? 0 : (tree)->vm_avl_height)
-/*
- * Consistency and balancing rules:
- * 1. tree->vm_avl_height == 1+max(heightof(tree->vm_avl_left),heightof(tree->vm_avl_right))
- * 2. abs( heightof(tree->vm_avl_left) - heightof(tree->vm_avl_right) ) <= 1
- * 3. foreach node in tree->vm_avl_left: node->vm_avl_key <= tree->vm_avl_key,
- *    foreach node in tree->vm_avl_right: node->vm_avl_key >= tree->vm_avl_key.
- */
-
-/* Look up the nodes at the left and at the right of a given node. */
-static inline void avl_neighbours (struct vm_area_struct * node, struct vm_area_struct * tree, struct vm_area_struct ** to_the_left, struct vm_area_struct ** to_the_right)
-{
-	vm_avl_key_t key = node->vm_avl_key;
-
-	*to_the_left = *to_the_right = NULL;
-	for (;;) {
-		if (tree == avl_empty) {
-			printk("avl_neighbours: node not found in the tree\n");
-			return;
-		}
-		if (key == tree->vm_avl_key)
-			break;
-		if (key < tree->vm_avl_key) {
-			*to_the_right = tree;
-			tree = tree->vm_avl_left;
-		} else {
-			*to_the_left = tree;
-			tree = tree->vm_avl_right;
-		}
-	}
-	if (tree != node) {
-		printk("avl_neighbours: node not exactly found in the tree\n");
-		return;
-	}
-	if (tree->vm_avl_left != avl_empty) {
-		struct vm_area_struct * node;
-		for (node = tree->vm_avl_left; node->vm_avl_right != avl_empty; node = node->vm_avl_right)
-			continue;
-		*to_the_left = node;
-	}
-	if (tree->vm_avl_right != avl_empty) {
-		struct vm_area_struct * node;
-		for (node = tree->vm_avl_right; node->vm_avl_left != avl_empty; node = node->vm_avl_left)
-			continue;
-		*to_the_right = node;
-	}
-	if ((*to_the_left && ((*to_the_left)->vm_next != node)) || (node->vm_next != *to_the_right))
-		printk("avl_neighbours: tree inconsistent with list\n");
-}
-
-/*
- * Rebalance a tree.
- * After inserting or deleting a node of a tree we have a sequence of subtrees
- * nodes[0]..nodes[k-1] such that
- * nodes[0] is the root and nodes[i+1] = nodes[i]->{vm_avl_left|vm_avl_right}.
- */
-static inline void avl_rebalance (struct vm_area_struct *** nodeplaces_ptr, int count)
-{
-	for ( ; count > 0 ; count--) {
-		struct vm_area_struct ** nodeplace = *--nodeplaces_ptr;
-		struct vm_area_struct * node = *nodeplace;
-		struct vm_area_struct * nodeleft = node->vm_avl_left;
-		struct vm_area_struct * noderight = node->vm_avl_right;
-		int heightleft = heightof(nodeleft);
-		int heightright = heightof(noderight);
-		if (heightright + 1 < heightleft) {
-			/*                                                      */
-			/*                            *                         */
-			/*                          /   \                       */
-			/*                       n+2      n                     */
-			/*                                                      */
-			struct vm_area_struct * nodeleftleft = nodeleft->vm_avl_left;
-			struct vm_area_struct * nodeleftright = nodeleft->vm_avl_right;
-			int heightleftright = heightof(nodeleftright);
-			if (heightof(nodeleftleft) >= heightleftright) {
-				/*                                                        */
-				/*                *                    n+2|n+3            */
-				/*              /   \                  /    \             */
-				/*           n+2      n      -->      /   n+1|n+2         */
-				/*           / \                      |    /    \         */
-				/*         n+1 n|n+1                 n+1  n|n+1  n        */
-				/*                                                        */
-				node->vm_avl_left = nodeleftright; nodeleft->vm_avl_right = node;
-				nodeleft->vm_avl_height = 1 + (node->vm_avl_height = 1 + heightleftright);
-				*nodeplace = nodeleft;
-			} else {
-				/*                                                        */
-				/*                *                     n+2               */
-				/*              /   \                 /     \             */
-				/*           n+2      n      -->    n+1     n+1           */
-				/*           / \                    / \     / \           */
-				/*          n  n+1                 n   L   R   n          */
-				/*             / \                                        */
-				/*            L   R                                       */
-				/*                                                        */
-				nodeleft->vm_avl_right = nodeleftright->vm_avl_left;
-				node->vm_avl_left = nodeleftright->vm_avl_right;
-				nodeleftright->vm_avl_left = nodeleft;
-				nodeleftright->vm_avl_right = node;
-				nodeleft->vm_avl_height = node->vm_avl_height = heightleftright;
-				nodeleftright->vm_avl_height = heightleft;
-				*nodeplace = nodeleftright;
-			}
-		}
-		else if (heightleft + 1 < heightright) {
-			/* similar to the above, just interchange 'left' <--> 'right' */
-			struct vm_area_struct * noderightright = noderight->vm_avl_right;
-			struct vm_area_struct * noderightleft = noderight->vm_avl_left;
-			int heightrightleft = heightof(noderightleft);
-			if (heightof(noderightright) >= heightrightleft) {
-				node->vm_avl_right = noderightleft; noderight->vm_avl_left = node;
-				noderight->vm_avl_height = 1 + (node->vm_avl_height = 1 + heightrightleft);
-				*nodeplace = noderight;
-			} else {
-				noderight->vm_avl_left = noderightleft->vm_avl_right;
-				node->vm_avl_right = noderightleft->vm_avl_left;
-				noderightleft->vm_avl_right = noderight;
-				noderightleft->vm_avl_left = node;
-				noderight->vm_avl_height = node->vm_avl_height = heightrightleft;
-				noderightleft->vm_avl_height = heightright;
-				*nodeplace = noderightleft;
-			}
-		}
-		else {
-			int height = (heightleft<heightright ? heightright : heightleft) + 1;
-			if (height == node->vm_avl_height)
-				break;
-			node->vm_avl_height = height;
-		}
-	}
-}
-
-/* Insert a node into a tree. */
-static inline void avl_insert (struct vm_area_struct * new_node, struct vm_area_struct ** ptree)
-{
-	vm_avl_key_t key = new_node->vm_avl_key;
-	struct vm_area_struct ** nodeplace = ptree;
-	struct vm_area_struct ** stack[avl_maxheight];
-	int stack_count = 0;
-	struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
-	for (;;) {
-		struct vm_area_struct * node = *nodeplace;
-		if (node == avl_empty)
-			break;
-		*stack_ptr++ = nodeplace; stack_count++;
-		if (key < node->vm_avl_key)
-			nodeplace = &node->vm_avl_left;
-		else
-			nodeplace = &node->vm_avl_right;
-	}
-	new_node->vm_avl_left = avl_empty;
-	new_node->vm_avl_right = avl_empty;
-	new_node->vm_avl_height = 1;
-	*nodeplace = new_node;
-	avl_rebalance(stack_ptr,stack_count);
-}
-
-/* Insert a node into a tree, and
- * return the node to the left of it and the node to the right of it.
- */
-static inline void avl_insert_neighbours (struct vm_area_struct * new_node, struct vm_area_struct ** ptree,
-	struct vm_area_struct ** to_the_left, struct vm_area_struct ** to_the_right)
-{
-	vm_avl_key_t key = new_node->vm_avl_key;
-	struct vm_area_struct ** nodeplace = ptree;
-	struct vm_area_struct ** stack[avl_maxheight];
-	int stack_count = 0;
-	struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
-	*to_the_left = *to_the_right = NULL;
-	for (;;) {
-		struct vm_area_struct * node = *nodeplace;
-		if (node == avl_empty)
-			break;
-		*stack_ptr++ = nodeplace; stack_count++;
-		if (key < node->vm_avl_key) {
-			*to_the_right = node;
-			nodeplace = &node->vm_avl_left;
-		} else {
-			*to_the_left = node;
-			nodeplace = &node->vm_avl_right;
-		}
-	}
-	new_node->vm_avl_left = avl_empty;
-	new_node->vm_avl_right = avl_empty;
-	new_node->vm_avl_height = 1;
-	*nodeplace = new_node;
-	avl_rebalance(stack_ptr,stack_count);
-}
-
-/* Removes a node out of a tree. */
-static inline void avl_remove (struct vm_area_struct * node_to_delete, struct vm_area_struct ** ptree)
-{
-	vm_avl_key_t key = node_to_delete->vm_avl_key;
-	struct vm_area_struct ** nodeplace = ptree;
-	struct vm_area_struct ** stack[avl_maxheight];
-	int stack_count = 0;
-	struct vm_area_struct *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
-	struct vm_area_struct ** nodeplace_to_delete;
-	for (;;) {
-		struct vm_area_struct * node = *nodeplace;
-		if (node == avl_empty) {
-			/* what? node_to_delete not found in tree? */
-			printk("avl_remove: node to delete not found in tree\n");
-			return;
-		}
-		*stack_ptr++ = nodeplace; stack_count++;
-		if (key == node->vm_avl_key)
-			break;
-		if (key < node->vm_avl_key)
-			nodeplace = &node->vm_avl_left;
-		else
-			nodeplace = &node->vm_avl_right;
-	}
-	nodeplace_to_delete = nodeplace;
-	/* Have to remove node_to_delete = *nodeplace_to_delete. */
-	if (node_to_delete->vm_avl_left == avl_empty) {
-		*nodeplace_to_delete = node_to_delete->vm_avl_right;
-		stack_ptr--; stack_count--;
-	} else {
-		struct vm_area_struct *** stack_ptr_to_delete = stack_ptr;
-		struct vm_area_struct ** nodeplace = &node_to_delete->vm_avl_left;
-		struct vm_area_struct * node;
-		for (;;) {
-			node = *nodeplace;
-			if (node->vm_avl_right == avl_empty)
-				break;
-			*stack_ptr++ = nodeplace; stack_count++;
-			nodeplace = &node->vm_avl_right;
-		}
-		*nodeplace = node->vm_avl_left;
-		/* node replaces node_to_delete */
-		node->vm_avl_left = node_to_delete->vm_avl_left;
-		node->vm_avl_right = node_to_delete->vm_avl_right;
-		node->vm_avl_height = node_to_delete->vm_avl_height;
-		*nodeplace_to_delete = node; /* replace node_to_delete */
-		*stack_ptr_to_delete = &node->vm_avl_left; /* replace &node_to_delete->vm_avl_left */
-	}
-	avl_rebalance(stack_ptr,stack_count);
-}
-
-#ifdef DEBUG_AVL
-
-/* print a list */
-static void printk_list (struct vm_area_struct * vma)
-{
-	printk("[");
-	while (vma) {
-		printk("%08lX-%08lX", vma->vm_start, vma->vm_end);
-		vma = vma->vm_next;
-		if (!vma)
-			break;
-		printk(" ");
-	}
-	printk("]");
-}
-
-/* print a tree */
-static void printk_avl (struct vm_area_struct * tree)
-{
-	if (tree != avl_empty) {
-		printk("(");
-		if (tree->vm_avl_left != avl_empty) {
-			printk_avl(tree->vm_avl_left);
-			printk("<");
-		}
-		printk("%08lX-%08lX", tree->vm_start, tree->vm_end);
-		if (tree->vm_avl_right != avl_empty) {
-			printk(">");
-			printk_avl(tree->vm_avl_right);
-		}
-		printk(")");
-	}
-}
-
-static char *avl_check_point = "somewhere";
-
-/* check a tree's consistency and balancing */
-static void avl_checkheights (struct vm_area_struct * tree)
-{
-	int h, hl, hr;
-
-	if (tree == avl_empty)
-		return;
-	avl_checkheights(tree->vm_avl_left);
-	avl_checkheights(tree->vm_avl_right);
-	h = tree->vm_avl_height;
-	hl = heightof(tree->vm_avl_left);
-	hr = heightof(tree->vm_avl_right);
-	if ((h == hl+1) && (hr <= hl) && (hl <= hr+1))
-		return;
-	if ((h == hr+1) && (hl <= hr) && (hr <= hl+1))
-		return;
-	printk("%s: avl_checkheights: heights inconsistent\n",avl_check_point);
-}
-
-/* check that all values stored in a tree are < key */
-static void avl_checkleft (struct vm_area_struct * tree, vm_avl_key_t key)
-{
-	if (tree == avl_empty)
-		return;
-	avl_checkleft(tree->vm_avl_left,key);
-	avl_checkleft(tree->vm_avl_right,key);
-	if (tree->vm_avl_key < key)
-		return;
-	printk("%s: avl_checkleft: left key %lu >= top key %lu\n",avl_check_point,tree->vm_avl_key,key);
-}
-
-/* check that all values stored in a tree are > key */
-static void avl_checkright (struct vm_area_struct * tree, vm_avl_key_t key)
-{
-	if (tree == avl_empty)
-		return;
-	avl_checkright(tree->vm_avl_left,key);
-	avl_checkright(tree->vm_avl_right,key);
-	if (tree->vm_avl_key > key)
-		return;
-	printk("%s: avl_checkright: right key %lu <= top key %lu\n",avl_check_point,tree->vm_avl_key,key);
-}
-
-/* check that all values are properly increasing */
-static void avl_checkorder (struct vm_area_struct * tree)
-{
-	if (tree == avl_empty)
-		return;
-	avl_checkorder(tree->vm_avl_left);
-	avl_checkorder(tree->vm_avl_right);
-	avl_checkleft(tree->vm_avl_left,tree->vm_avl_key);
-	avl_checkright(tree->vm_avl_right,tree->vm_avl_key);
-}
-
-/* all checks */
-static void avl_check (struct task_struct * task, char *caller)
-{
-	avl_check_point = caller;
-/*	printk("task \"%s\", %s\n",task->comm,caller); */
-/*	printk("task \"%s\" list: ",task->comm); printk_list(task->mm->mmap); printk("\n"); */
-/*	printk("task \"%s\" tree: ",task->comm); printk_avl(task->mm->mmap_avl); printk("\n"); */
-	avl_checkheights(task->mm->mmap_avl);
-	avl_checkorder(task->mm->mmap_avl);
-}
-
-#endif
-
-
-/*
- * Normal function to fix up a mapping
+/* Normal function to fix up a mapping
  * This function is the default for when an area has no specific
  * function.  This may be used as part of a more specific routine.
  * This function works out what part of an area is affected and
@@ -738,19 +379,11 @@
 	struct vm_area_struct *mpnt;
 	unsigned long end = addr + len;
 
-	if (addr < area->vm_start || addr >= area->vm_end ||
-	    end <= area->vm_start || end > area->vm_end ||
-	    end < addr)
-	{
-		printk("unmap_fixup: area=%lx-%lx, unmap %lx-%lx!!\n",
-		       area->vm_start, area->vm_end, addr, end);
-		return;
-	}
 	area->vm_mm->total_vm -= len >> PAGE_SHIFT;
 	if (area->vm_flags & VM_LOCKED)
 		area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
 
-	/* Unmapping the whole area */
+	/* Unmapping the whole area. */
 	if (addr == area->vm_start && end == area->vm_end) {
 		if (area->vm_ops && area->vm_ops->close)
 			area->vm_ops->close(area);
@@ -759,15 +392,13 @@
 		return;
 	}
 
-	/* Work out to one of the ends */
+	/* Work out to one of the ends. */
 	if (end == area->vm_end)
 		area->vm_end = addr;
-	else
-	if (addr == area->vm_start) {
+	else if (addr == area->vm_start) {
 		area->vm_offset += (end - area->vm_start);
 		area->vm_start = end;
-	}
-	else {
+	} else {
 	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
 		/* Add end mapping -- leave beginning for below */
 		mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
@@ -785,7 +416,7 @@
 		insert_vm_struct(current->mm, mpnt);
 	}
 
-	/* construct whatever mapping is needed */
+	/* Construct whatever mapping is needed. */
 	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!mpnt)
 		return;
@@ -809,15 +440,14 @@
 	return ret;
 }
 
-/*
- * Munmap is split into 2 main parts -- this part which finds
+/* Munmap is split into 2 main parts -- this part which finds
  * what needs doing, and the areas themselves, which do the
  * work.  This now handles partial unmappings.
  * Jeremy Fitzhardine <jeremy@sw.oz.au>
  */
 int do_munmap(unsigned long addr, size_t len)
 {
-	struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
+	struct vm_area_struct *mpnt, *next, *free;
 
 	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
 		return -EINVAL;
@@ -825,33 +455,36 @@
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return 0;
 
-	/*
-	 * Check if this memory area is ok - put it on the temporary
+	/* Check if this memory area is ok - put it on the temporary
 	 * list if so..  The checks here are pretty simple --
 	 * every area affected in some way (by any overlap) is put
 	 * on the list.  If nothing is put on, nothing is affected.
 	 */
-	mpnt = find_vma(current->mm, addr);
+	mpnt = current->mm->mmap;
+	while(mpnt && mpnt->vm_end <= addr)
+		mpnt = mpnt->vm_next;
 	if (!mpnt)
 		return 0;
-	avl_neighbours(mpnt, current->mm->mmap_avl, &prev, &next);
-	/* we have  prev->vm_next == mpnt && mpnt->vm_next = next */
-	/* and  addr < mpnt->vm_end  */
 
-	npp = (prev ? &prev->vm_next : &current->mm->mmap);
+	next = mpnt->vm_next;
+
+	/* we have mpnt->vm_next = next and addr < mpnt->vm_end */
 	free = NULL;
-	for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {
-		*npp = mpnt->vm_next;
+	for ( ; mpnt && mpnt->vm_start < addr+len; ) {
+		struct vm_area_struct *next = mpnt->vm_next;
+
+		if(mpnt->vm_next)
+			mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
+		*mpnt->vm_pprev = mpnt->vm_next;
+
 		mpnt->vm_next = free;
 		free = mpnt;
-		avl_remove(mpnt, &current->mm->mmap_avl);
+		mpnt = next;
 	}
-
 	if (free == NULL)
 		return 0;
 
-	/*
-	 * Ok - we have the memory areas we should free on the 'free' list,
+	/* Ok - we have the memory areas we should free on the 'free' list,
 	 * so release them, and unmap the page range..
 	 * If the one of the segments is only being partially unmapped,
 	 * it will put new vm_area_struct(s) into the address space.
@@ -871,36 +504,27 @@
 
 		if (mpnt->vm_ops && mpnt->vm_ops->unmap)
 			mpnt->vm_ops->unmap(mpnt, st, size);
+
 		flush_cache_range(current->mm, st, end);
 		zap_page_range(current->mm, st, size);
 		flush_tlb_range(current->mm, st, end);
+
 		unmap_fixup(mpnt, st, size);
+
 		kmem_cache_free(vm_area_cachep, mpnt);
 	} while (free);
 
-	/* we could zap the page tables here too.. */
-
+	current->mm->mmap_cache = NULL;		/* Kill the cache. */
 	return 0;
 }
 
-/* Build the AVL tree corresponding to the VMA list. */
-void build_mmap_avl(struct mm_struct * mm)
-{
-	struct vm_area_struct * vma;
-
-	mm->mmap_avl = NULL;
-	for (vma = mm->mmap; vma; vma = vma->vm_next)
-		avl_insert(vma, &mm->mmap_avl);
-}
-
 /* Release all mmaps. */
 void exit_mmap(struct mm_struct * mm)
 {
 	struct vm_area_struct * mpnt;
 
 	mpnt = mm->mmap;
-	mm->mmap = NULL;
-	mm->mmap_avl = NULL;
+	mm->mmap = mm->mmap_cache = NULL;
 	mm->rss = 0;
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
@@ -925,81 +549,38 @@
 	}
 }
 
-/*
- * Insert vm structure into process list sorted by address
+/* Insert vm structure into process list sorted by address
  * and into the inode's i_mmap ring.
  */
 void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
 {
-	struct vm_area_struct *share;
+	struct vm_area_struct **pprev = &mm->mmap;
 	struct inode * inode;
 
-#if 0 /* equivalent, but slow */
-	struct vm_area_struct **p, *mpnt;
-
-	p = &mm->mmap;
-	while ((mpnt = *p) != NULL) {
-		if (mpnt->vm_start > vmp->vm_start)
-			break;
-		if (mpnt->vm_end > vmp->vm_start)
-			printk("insert_vm_struct: overlapping memory areas\n");
-		p = &mpnt->vm_next;
-	}
-	vmp->vm_next = mpnt;
-	*p = vmp;
-#else
-	struct vm_area_struct * prev, * next;
-
-	avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
-	if ((prev ? prev->vm_next : mm->mmap) != next)
-		printk("insert_vm_struct: tree inconsistent with list\n");
-	if (prev)
-		prev->vm_next = vmp;
-	else
-		mm->mmap = vmp;
-	vmp->vm_next = next;
-#endif
+	/* Find where to link it in. */
+	while(*pprev && (*pprev)->vm_start <= vmp->vm_start)
+		pprev = &(*pprev)->vm_next;
+
+	/* Insert it. */
+	if((vmp->vm_next = *pprev) != NULL)
+		(*pprev)->vm_pprev = &vmp->vm_next;
+	*pprev = vmp;
+	vmp->vm_pprev = pprev;
 
 	inode = vmp->vm_inode;
-	if (!inode)
-		return;
-
-	/* insert vmp into inode's circular share list */
-	if ((share = inode->i_mmap)) {
-		vmp->vm_next_share = share->vm_next_share;
-		vmp->vm_next_share->vm_prev_share = vmp;
-		share->vm_next_share = vmp;
-		vmp->vm_prev_share = share;
-	} else
-		inode->i_mmap = vmp->vm_next_share = vmp->vm_prev_share = vmp;
-}
-
-/*
- * Remove one vm structure from the inode's i_mmap ring.
- */
-void remove_shared_vm_struct(struct vm_area_struct *mpnt)
-{
-	struct inode * inode = mpnt->vm_inode;
-
-	if (!inode)
-		return;
-
-	if (mpnt->vm_next_share == mpnt) {
-		if (inode->i_mmap != mpnt)
-			printk("Inode i_mmap ring corrupted\n");
-		inode->i_mmap = NULL;
-		return;
+	if (inode) {
+		if (vmp->vm_flags & VM_DENYWRITE)
+			inode->i_writecount--;
+      
+		/* insert vmp into inode's share list */
+		if((vmp->vm_next_share = inode->i_mmap) != NULL)
+			inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
+		inode->i_mmap = vmp;
+		vmp->vm_pprev_share = &inode->i_mmap;
 	}
-
-	if (inode->i_mmap == mpnt)
-		inode->i_mmap = mpnt->vm_next_share;
-
-	mpnt->vm_prev_share->vm_next_share = mpnt->vm_next_share;
-	mpnt->vm_next_share->vm_prev_share = mpnt->vm_prev_share;
 }
 
-/*
- * Merge the list of memory segments if possible.
+/* Merge the list of memory segments if possible.
  * Redundant vm_area_structs are freed.
  * This assumes that the list is ordered by address.
  * We don't need to traverse the entire list, only those segments
@@ -1010,13 +591,19 @@
 	struct vm_area_struct *prev, *mpnt, *next;
 
 	down(&mm->mmap_sem);
-	mpnt = find_vma(mm, start_addr);
+
+	prev = NULL;
+	mpnt = mm->mmap;
+	while(mpnt && mpnt->vm_end <= start_addr) {
+		prev = mpnt;
+		mpnt = mpnt->vm_next;
+	}
 	if (!mpnt)
 		goto no_vma;
 
-	avl_neighbours(mpnt, mm->mmap_avl, &prev, &next);
-	/* we have  prev->vm_next == mpnt && mpnt->vm_next = next */
+	next = mpnt->vm_next;
 
+	/* we have prev->vm_next == mpnt && mpnt->vm_next = next */
 	if (!prev) {
 		prev = mpnt;
 		mpnt = next;
@@ -1026,41 +613,32 @@
 	 * start_addr < mpnt->vm_end && prev->vm_start < end_addr
 	 */
 	for ( ; mpnt && prev->vm_start < end_addr ; prev = mpnt, mpnt = next) {
-#if 0
-		printk("looping in merge_segments, mpnt=0x%lX\n", (unsigned long) mpnt);
-#endif
-
 		next = mpnt->vm_next;
 
-		/*
-		 * To share, we must have the same inode, operations.. 
-		 */
-		if (mpnt->vm_inode != prev->vm_inode)
-			continue;
-		if (mpnt->vm_pte != prev->vm_pte)
-			continue;
-		if (mpnt->vm_ops != prev->vm_ops)
-			continue;
-		if (mpnt->vm_flags != prev->vm_flags)
+		/* To share, we must have the same inode, operations.. */
+		if ((mpnt->vm_inode != prev->vm_inode)	||
+		    (mpnt->vm_pte != prev->vm_pte)	||
+		    (mpnt->vm_ops != prev->vm_ops)	||
+		    (mpnt->vm_flags != prev->vm_flags)	||
+		    (prev->vm_end != mpnt->vm_start))
 			continue;
-		if (prev->vm_end != mpnt->vm_start)
-			continue;
-		/*
-		 * and if we have an inode, the offsets must be contiguous..
-		 */
+
+		/* and if we have an inode, the offsets must be contiguous.. */
 		if ((mpnt->vm_inode != NULL) || (mpnt->vm_flags & VM_SHM)) {
-			if (prev->vm_offset + prev->vm_end - prev->vm_start != mpnt->vm_offset)
+			unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
+			if (off != mpnt->vm_offset)
 				continue;
 		}
 
-		/*
-		 * merge prev with mpnt and set up pointers so the new
+		/* merge prev with mpnt and set up pointers so the new
 		 * big segment can possibly merge with the next one.
 		 * The old unused mpnt is freed.
 		 */
-		avl_remove(mpnt, &mm->mmap_avl);
+		if(mpnt->vm_next)
+			mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
+		*mpnt->vm_pprev = mpnt->vm_next;
+
 		prev->vm_end = mpnt->vm_end;
-		prev->vm_next = mpnt->vm_next;
 		if (mpnt->vm_ops && mpnt->vm_ops->close) {
 			mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
 			mpnt->vm_start = mpnt->vm_end;
@@ -1072,11 +650,12 @@
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = prev;
 	}
+	mm->mmap_cache = NULL;		/* Kill the cache. */
 no_vma:
 	up(&mm->mmap_sem);
 }
 
-void vma_init(void)
+__initfunc(void vma_init(void))
 {
 	vm_area_cachep = kmem_cache_create("vm_area_struct",
 					   sizeof(struct vm_area_struct),
@@ -1084,4 +663,11 @@
 					   NULL, NULL);
 	if(!vm_area_cachep)
 		panic("vma_init: Cannot alloc vm_area_struct cache.");
+
+	mm_cachep = kmem_cache_create("mm_struct",
+				      sizeof(struct mm_struct),
+				      sizeof(long) * 4, SLAB_HWCACHE_ALIGN,
+				      NULL, NULL);
+	if(!mm_cachep)
+		panic("vma_init: Cannot alloc mm_struct cache.");
 }
diff -u --recursive --new-file v2.1.36/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.36/linux/mm/page_alloc.c	Wed Apr 23 19:01:29 1997
+++ linux/mm/page_alloc.c	Mon May 12 17:39:50 1997
@@ -18,12 +18,14 @@
 #include <linux/fs.h>
 #include <linux/swapctl.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
 #include <asm/uaccess.h> /* for copy_to/from_user */
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
+#include <asm/spinlock.h>
 
 int nr_swap_pages = 0;
 int nr_free_pages = 0;
@@ -88,10 +90,6 @@
  *
  * With the above two rules, you get a straight-line execution path
  * for the normal case, giving better asm-code.
- *
- * free_page() may sleep since the page being freed may be a buffer
- * page or present in the swap cache. It will not sleep, however,
- * for a freshly allocated page (get_free_page()).
  */
 
 /*
@@ -99,6 +97,8 @@
  *
  * Hint: -mask = 1+~mask
  */
+static spinlock_t page_alloc_lock;
+
 static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 {
 	struct free_area_struct *area = free_area + order;
@@ -106,15 +106,14 @@
 	unsigned long mask = (~0UL) << order;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&page_alloc_lock, flags);
 
 #define list(x) (mem_map+(x))
 
 	map_nr &= mask;
 	nr_free_pages -= mask;
 	while (mask + (1 << (NR_MEM_LISTS-1))) {
-		if (!change_bit(index, area->map))
+		if (!test_and_change_bit(index, area->map))
 			break;
 		remove_mem_queue(list(map_nr ^ -mask));
 		mask <<= 1;
@@ -126,7 +125,7 @@
 
 #undef list
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&page_alloc_lock, flags);
 }
 
 void __free_page(struct page *page)
@@ -172,7 +171,7 @@
 				MARK_USED(map_nr, new_order, area); \
 				nr_free_pages -= 1 << order; \
 				EXPAND(ret, map_nr, order, new_order, area); \
-				restore_flags(flags); \
+				spin_unlock_irqrestore(&page_alloc_lock, flags); \
 				return ADDRESS(map_nr); \
 			} \
 			prev = ret; \
@@ -214,15 +213,14 @@
 	reserved_pages = 5;
 	if (priority != GFP_NFS)
 		reserved_pages = min_free_pages;
-	save_flags(flags);
 repeat:
-	cli();
+	spin_lock_irqsave(&page_alloc_lock, flags);
 	if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
 		RMQUEUE(order, dma);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&page_alloc_lock, flags);
 		return 0;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&page_alloc_lock, flags);
 	if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
 		goto repeat;
 	return 0;
@@ -239,8 +237,7 @@
  	unsigned long total = 0;
 
 	printk("Free pages:      %6dkB\n ( ",nr_free_pages<<(PAGE_SHIFT-10));
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&page_alloc_lock, flags);
  	for (order=0 ; order < NR_MEM_LISTS; order++) {
 		struct page * tmp;
 		unsigned long nr = 0;
@@ -250,7 +247,7 @@
 		total += nr * ((PAGE_SIZE>>10) << order);
 		printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&page_alloc_lock, flags);
 	printk("= %lukB)\n", total);
 #ifdef SWAP_CACHE_INFO
 	show_swap_cache_info();
@@ -265,7 +262,7 @@
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
-unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem))
 {
 	mem_map_t * p;
 	unsigned long mask = PAGE_MASK;
@@ -273,7 +270,7 @@
 
 	/*
 	 * select nr of pages we try to keep free for important stuff
-	 * with a minimum of 16 pages. This is totally arbitrary
+	 * with a minimum of 48 pages. This is totally arbitrary
 	 */
 	i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
 	if (i < 48)
diff -u --recursive --new-file v2.1.36/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.36/linux/mm/page_io.c	Mon Dec 23 01:13:52 1996
+++ linux/mm/page_io.c	Mon May 12 10:35:44 1997
@@ -67,7 +67,7 @@
 		return;
 	}
 	/* Make sure we are the only process doing I/O with this swap page. */
-	while (set_bit(offset,p->swap_lockmap)) {
+	while (test_and_set_bit(offset,p->swap_lockmap)) {
 		run_task_queue(&tq_disk);
 		sleep_on(&lock_queue);
 	}
@@ -136,7 +136,7 @@
 	} else
 		printk("rw_swap_page: no swap file or device\n");
 	atomic_dec(&page->count);
-	if (offset && !clear_bit(offset,p->swap_lockmap))
+	if (offset && !test_and_clear_bit(offset,p->swap_lockmap))
 		printk("rw_swap_page: lock already cleared\n");
 	wake_up(&lock_queue);
 }
@@ -158,7 +158,7 @@
 		printk("swap_after_unlock_page: weirdness\n");
 		return;
 	}
-	if (!clear_bit(offset,p->swap_lockmap))
+	if (!test_and_clear_bit(offset,p->swap_lockmap))
 		printk("swap_after_unlock_page: lock already cleared\n");
 	wake_up(&lock_queue);
 }
@@ -187,7 +187,7 @@
 			panic("ll_rw_page: bad block dev cmd, must be R/W");
 	}
 	page = mem_map + MAP_NR(buffer);
-	if (set_bit(PG_locked, &page->flags))
+	if (test_and_set_bit(PG_locked, &page->flags))
 		panic ("ll_rw_page: page already locked");
 	brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
 }
diff -u --recursive --new-file v2.1.36/linux/mm/slab.c linux/mm/slab.c
--- v2.1.36/linux/mm/slab.c	Mon Apr 14 16:28:27 1997
+++ linux/mm/slab.c	Mon May 12 10:35:44 1997
@@ -16,6 +16,7 @@
 #include	<linux/slab.h>
 #include	<linux/mm.h>
 #include	<linux/interrupt.h>
+#include	<linux/init.h>
 #include	<asm/system.h>
 #include	<asm/cache.h>
 
@@ -269,8 +270,8 @@
 static	kmem_cache_t	*clock_searchp = &cache_cache;
 
 /* Init an internal cache */
-static void
-kmem_own_cache_init(kmem_cache_t *cachep)
+__initfunc(static void
+kmem_own_cache_init(kmem_cache_t *cachep))
 {
 	unsigned long	size, i;
 
@@ -293,8 +294,8 @@
 }
 
 /* Initialisation - setup all internal caches */
-long
-kmem_cache_init(long start, long end)
+__initfunc(long
+kmem_cache_init(long start, long end))
 {
 	/* sanity */
 #define	kmem_cache_offset(x) ((unsigned long)&((kmem_cache_t *)0)->x)
@@ -319,8 +320,8 @@
 }
 
 /* Initialisation - setup general caches */
-void
-kmem_cache_sizes_init(void)
+__initfunc(void
+kmem_cache_sizes_init(void))
 {
 	unsigned long	i;
 
diff -u --recursive --new-file v2.1.36/linux/mm/swap.c linux/mm/swap.c
--- v2.1.36/linux/mm/swap.c	Wed Apr 23 19:01:29 1997
+++ linux/mm/swap.c	Mon May 12 10:35:44 1997
@@ -23,6 +23,7 @@
 #include <linux/fs.h>
 #include <linux/swapctl.h>
 #include <linux/pagemap.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -67,7 +68,7 @@
 /* General swap control */
 
 /* Parse the kernel command line "swap=" option at load time: */
-void swap_setup(char *str, int *ints)
+__initfunc(void swap_setup(char *str, int *ints))
 {
 	int * swap_vars[8] = {
 		&MAX_PAGE_AGE,
@@ -87,7 +88,7 @@
 }
 
 /* Parse the kernel command line "buff=" option at load time: */
-void buff_setup(char *str, int *ints)
+__initfunc(void buff_setup(char *str, int *ints))
 {
 	int * buff_vars[6] = {
 		&MAX_BUFF_AGE,
diff -u --recursive --new-file v2.1.36/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.1.36/linux/mm/swap_state.c	Mon Oct 28 04:21:41 1996
+++ linux/mm/swap_state.c	Mon May 12 10:35:44 1997
@@ -16,6 +16,7 @@
 #include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/swapctl.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -69,8 +70,8 @@
 	return 0;
 }
 
-unsigned long init_swap_cache(unsigned long mem_start,
-	unsigned long mem_end)
+__initfunc(unsigned long init_swap_cache(unsigned long mem_start,
+					 unsigned long mem_end))
 {
 	unsigned long swap_cache_size;
 
diff -u --recursive --new-file v2.1.36/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.36/linux/mm/swapfile.c	Tue Jan 28 00:02:45 1997
+++ linux/mm/swapfile.c	Mon May 12 10:35:44 1997
@@ -298,24 +298,25 @@
  */
 static int try_to_unuse(unsigned int type)
 {
-	int nr;
 	unsigned long page = get_free_page(GFP_KERNEL);
+	struct task_struct *p;
 
 	if (!page)
 		return -ENOMEM;
-	nr = 0;
-	while (nr < NR_TASKS) {
-		struct task_struct * p = task[nr];
-		if (p) {
-			if (unuse_process(p->mm, type, page)) {
-				page = get_free_page(GFP_KERNEL);
-				if (!page)
-					return -ENOMEM;
-				continue;
-			}
+again:
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		read_unlock(&tasklist_lock);
+		if(unuse_process(p->mm, type, page)) {
+			page = get_free_page(GFP_KERNEL);
+			if(!page)
+				return -ENOMEM;
+			goto again;
 		}
-		nr++;
+		read_lock(&tasklist_lock);
 	}
+	read_unlock(&tasklist_lock);
+
 	free_page(page);
 	return 0;
 }
diff -u --recursive --new-file v2.1.36/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.36/linux/mm/vmscan.c	Mon Apr 14 16:28:27 1997
+++ linux/mm/vmscan.c	Mon May 12 10:35:44 1997
@@ -271,54 +271,72 @@
 
 static int swap_out(unsigned int priority, int dma, int wait)
 {
-	static int swap_task;
-	int loop, counter;
+	static int skip_factor = 0;
+	int limit = nr_tasks - 1;
+	int loop, counter, i;
 	struct task_struct *p;
 
 	counter = ((PAGEOUT_WEIGHT * nr_tasks) >> 10) >> priority;
+	if(skip_factor > nr_tasks)
+		skip_factor = 0;
+
+	read_lock(&tasklist_lock);
+	p = init_task.next_task;
+	i = skip_factor;
+	while(i--)
+		p = p->next_task;
 	for(; counter >= 0; counter--) {
-		/*
-		 * Check that swap_task is suitable for swapping.  If not, look for
-		 * the next suitable process.
-		 */
+		/* Check if task is suitable for swapping. */
 		loop = 0;
 		while(1) {
-			if (swap_task >= NR_TASKS) {
-				swap_task = 1;
+			if(!--limit) {
+				limit = nr_tasks - 1;
+				/* See if all processes are unswappable or
+				 * already swapped out.
+				 */
 				if (loop)
-					/* all processes are unswappable or already swapped out */
-					return 0;
+					goto out;
 				loop = 1;
 			}
-
-			p = task[swap_task];
-			if (p && p->swappable && p->mm->rss)
+			if (p->swappable && p->mm->rss)
 				break;
-
-			swap_task++;
+			if((p = p->next_task) == &init_task)
+				p = p->next_task;
 		}
+		skip_factor++;
 
-		/*
-		 * Determine the number of pages to swap from this process.
-		 */
+		/* Determine the number of pages to swap from this process. */
 		if (!p->swap_cnt) {
- 			/* Normalise the number of pages swapped by
+			/* Normalise the number of pages swapped by
 			   multiplying by (RSS / 1MB) */
 			p->swap_cnt = AGE_CLUSTER_SIZE(p->mm->rss);
 		}
 		if (!--p->swap_cnt)
-			swap_task++;
+			skip_factor++;
+		read_unlock(&tasklist_lock);
+
 		switch (swap_out_process(p, dma, wait)) {
-			case 0:
-				if (p->swap_cnt)
-					swap_task++;
-				break;
-			case 1:
-				return 1;
-			default:
-				break;
-		}
+		case 0:
+			if (p->swap_cnt)
+				skip_factor++;
+			break;
+		case 1:
+			return 1;
+		default:
+			break;
+		};
+
+		/* Whoever we swapped may not even exist now, in fact we cannot
+		 * assume anything about the list we were searching previously.
+		 */
+		read_lock(&tasklist_lock);
+		p = init_task.next_task;
+		i = skip_factor;
+		while(i--)
+			p = p->next_task;
 	}
+out:
+	read_unlock(&tasklist_lock);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.36/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c
--- v2.1.36/linux/net/802/llc_macinit.c	Thu Feb 27 10:57:32 1997
+++ linux/net/802/llc_macinit.c	Mon May 12 10:35:44 1997
@@ -26,6 +26,7 @@
 #include <linux/malloc.h>
 #include <linux/unistd.h>
 #include <linux/netdevice.h>
+#include <linux/init.h>
 #include <net/p8022.h>
 
 #include <asm/byteorder.h>
@@ -202,7 +203,7 @@
 
 #define ALL_TYPES_8022 0
 
-void llc_init(struct net_proto *proto)
+__initfunc(void llc_init(struct net_proto *proto))
 {
 	printk(KERN_NOTICE "IEEE 802.2 LLC for Linux 2.1 (c) 1996 Tim Alpaerts\n");
 	return;
diff -u --recursive --new-file v2.1.36/linux/net/802/p8022.c linux/net/802/p8022.c
--- v2.1.36/linux/net/802/p8022.c	Fri Feb  7 05:54:55 1997
+++ linux/net/802/p8022.c	Mon May 12 10:35:44 1997
@@ -23,6 +23,7 @@
 #include <net/datalink.h>
 #include <linux/mm.h>
 #include <linux/in.h>
+#include <linux/init.h>
 #include <net/p8022.h>
 
 static struct datalink_proto *p8022_list = NULL;
@@ -90,7 +91,7 @@
 EXPORT_SYMBOL(register_8022_client);
 EXPORT_SYMBOL(unregister_8022_client);
 
-void p8022_proto_init(struct net_proto *pro)
+__initfunc(void p8022_proto_init(struct net_proto *pro))
 {
 	p8022_packet_type.type=htons(ETH_P_802_2);
 	dev_add_pack(&p8022_packet_type);
diff -u --recursive --new-file v2.1.36/linux/net/802/p8022tr.c linux/net/802/p8022tr.c
--- v2.1.36/linux/net/802/p8022tr.c	Fri Jan  3 01:33:27 1997
+++ linux/net/802/p8022tr.c	Mon May 12 10:35:44 1997
@@ -15,6 +15,7 @@
 #include <net/datalink.h>
 #include <linux/mm.h>
 #include <linux/in.h>
+#include <linux/init.h>
 #include <net/p8022tr.h>
 
 #define SNAP_HEADER_LEN	8
@@ -91,7 +92,7 @@
 EXPORT_SYMBOL(register_8022tr_client);
 EXPORT_SYMBOL(unregister_8022tr_client);
 
-void p8022tr_proto_init(struct net_proto *pro)
+__initfunc(void p8022tr_proto_init(struct net_proto *pro))
 {
 	p8022tr_packet_type.type=htons(ETH_P_TR_802_2);
 	dev_add_pack(&p8022tr_packet_type);
diff -u --recursive --new-file v2.1.36/linux/net/802/psnap.c linux/net/802/psnap.c
--- v2.1.36/linux/net/802/psnap.c	Fri Jan  3 01:33:27 1997
+++ linux/net/802/psnap.c	Mon May 12 10:35:44 1997
@@ -19,6 +19,7 @@
 #include <net/psnap.h>
 #include <linux/mm.h>
 #include <linux/in.h>
+#include <linux/init.h>
 
 static struct datalink_proto *snap_list = NULL;
 static struct datalink_proto *snap_dl = NULL;		/* 802.2 DL for SNAP */
@@ -87,7 +88,7 @@
 EXPORT_SYMBOL(register_snap_client);
 EXPORT_SYMBOL(unregister_snap_client);
 
-void snap_proto_init(struct net_proto *pro)
+__initfunc(void snap_proto_init(struct net_proto *pro))
 {
 	snap_dl=register_8022_client(0xAA, snap_rcv);
 	if(snap_dl==NULL)
diff -u --recursive --new-file v2.1.36/linux/net/802/tr.c linux/net/802/tr.c
--- v2.1.36/linux/net/802/tr.c	Mon Apr 14 16:28:27 1997
+++ linux/net/802/tr.c	Mon May 12 10:35:44 1997
@@ -31,6 +31,7 @@
 #include <linux/timer.h>
 #include <linux/net.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 #include <net/arp.h>
 
 static void tr_source_route(struct trh_hdr *trh, struct device *dev);
@@ -460,7 +461,7 @@
  *	too much for this.
  */
  
-void rif_init(struct net_proto *unused) 
+__initfunc(void rif_init(struct net_proto *unused))
 {
 
 	rif_timer.expires  = RIF_TIMEOUT;
diff -u --recursive --new-file v2.1.36/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v2.1.36/linux/net/appletalk/aarp.c	Sun Feb  2 05:18:48 1997
+++ linux/net/appletalk/aarp.c	Mon May 12 10:35:44 1997
@@ -47,6 +47,7 @@
 #include <net/datalink.h>
 #include <net/psnap.h>
 #include <linux/atalk.h>
+#include <linux/init.h>
 
 /*
  *	Lists of aarp entries
@@ -796,7 +797,7 @@
 static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3};
 
 
-void aarp_proto_init(void)
+__initfunc(void aarp_proto_init(void))
 {
 	if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
 		printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
diff -u --recursive --new-file v2.1.36/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.36/linux/net/appletalk/ddp.c	Mon Apr 14 16:28:27 1997
+++ linux/net/appletalk/ddp.c	Mon May 12 10:35:44 1997
@@ -67,6 +67,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/firewall.h>
+#include <linux/init.h>
 
 
 #undef APPLETALK_DEBUG
@@ -2034,7 +2035,7 @@
 
 /* Called by proto.c on kernel start up */
 
-void atalk_proto_init(struct net_proto *pro)
+__initfunc(void atalk_proto_init(struct net_proto *pro))
 {
 	(void) sock_register(&atalk_family_ops);
 	if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL)
diff -u --recursive --new-file v2.1.36/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.36/linux/net/ax25/af_ax25.c	Mon Apr 14 16:28:27 1997
+++ linux/net/ax25/af_ax25.c	Mon May 12 10:35:44 1997
@@ -126,6 +126,7 @@
 #include <linux/stat.h>
 #include <linux/firewall.h>
 #include <linux/sysctl.h>
+#include <linux/init.h>
 #include <net/ip.h>
 #include <net/arp.h>
 
@@ -1795,7 +1796,7 @@
 };
 #endif
 
-void ax25_proto_init(struct net_proto *pro)
+__initfunc(void ax25_proto_init(struct net_proto *pro))
 {
 	sock_register(&ax25_family_ops);
 	ax25_packet_type.type = htons(ETH_P_AX25);
diff -u --recursive --new-file v2.1.36/linux/net/core/firewall.c linux/net/core/firewall.c
--- v2.1.36/linux/net/core/firewall.c	Thu Mar 27 14:40:14 1997
+++ linux/net/core/firewall.c	Mon May 12 10:35:44 1997
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
+#include <linux/init.h>
 #include <asm/semaphore.h>
 
 struct semaphore firewall_sem = MUTEX; 
@@ -150,7 +151,7 @@
 EXPORT_SYMBOL(call_out_firewall);
 EXPORT_SYMBOL(call_fw_firewall);
 
-void fwchain_init(void)
+__initfunc(void fwchain_init(void))
 {
 	int i;
 	for(i=0;i<NPROTO;i++)
diff -u --recursive --new-file v2.1.36/linux/net/core/scm.c linux/net/core/scm.c
--- v2.1.36/linux/net/core/scm.c	Sun Jan 26 03:40:46 1997
+++ linux/net/core/scm.c	Mon May 12 10:35:44 1997
@@ -243,7 +243,7 @@
 	int i;
 	struct file **fp = scm->fp->fp;
 
-	if (fdnum > fdmax)
+	if (fdnum < fdmax)
 		fdmax = fdnum;
 
 	for (i=0, cmfptr=(int*)cm->cmsg_data; i<fdmax; i++, cmfptr++)
@@ -253,7 +253,6 @@
 			break;
 		current->files->fd[new_fd] = fp[i];
 		err = put_user(new_fd, cmfptr);
-		cmfptr++;
 	}
 
 	if (i > 0)
diff -u --recursive --new-file v2.1.36/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.36/linux/net/core/skbuff.c	Wed Apr 23 19:01:29 1997
+++ linux/net/core/skbuff.c	Mon May 12 10:35:44 1997
@@ -64,6 +64,7 @@
 static atomic_t net_allocs = ATOMIC_INIT(0);
 static atomic_t net_fails  = ATOMIC_INIT(0);
 
+
 extern atomic_t ip_frag_mem;
 
 /*
diff -u --recursive --new-file v2.1.36/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.36/linux/net/core/sock.c	Wed Apr 23 19:01:29 1997
+++ linux/net/core/sock.c	Mon May 12 10:35:44 1997
@@ -118,6 +118,12 @@
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
+/* Run time adjustable parameters. */
+__u32 sysctl_wmem_max = SK_WMEM_MAX;
+__u32 sysctl_rmem_max = SK_RMEM_MAX;
+__u32 sysctl_wmem_default = SK_WMEM_MAX;
+__u32 sysctl_rmem_default = SK_RMEM_MAX;
+
 /*
  *	This is meant for all protocols to use and covers goings on
  *	at the socket level. Everything here is generic.
@@ -146,13 +152,8 @@
 	}
 #endif	
 		
-  	if(optlen<sizeof(int)) {
-#if 1 /* DaveM Debugging */
-		printk("sock_setsockopt: optlen is %d, going on anyways.\n", optlen);
-#else
+  	if(optlen<sizeof(int))
   		return(-EINVAL);
-#endif
-	}
   	
 	err = get_user(val, (int *)optval);
 	if (err)
@@ -189,15 +190,15 @@
 			 *	is best
 			 */
 			 
-			if(val > SK_WMEM_MAX*2)
+			/* printk(KERN_DEBUG "setting SO_SNDBUF %d\n", val); */
+			if (val > sysctl_wmem_max)
 				return -EINVAL;
-			/*
-			 *	Once this is all 32bit values we can
-			 *	drop this check.
+
+			/* FIXME: the tcp code should be made to work even
+			 * with small sndbuf values.
 			 */
-			if(val > 65535)
-				return -EINVAL;
-			sk->sndbuf = max(val,2048);
+			sk->sndbuf = max(val*2,2048);
+
 			/*
 			 *	Wake up sending tasks if we
 			 *	upped the value.
@@ -206,12 +207,13 @@
 			break;
 
 		case SO_RCVBUF:
-			if(val > SK_RMEM_MAX*2)
-				return -EINVAL;
-			/* Can go soon: FIXME */
-			if(val > 65535)
+			/* printk(KERN_DEBUG "setting SO_RCVBUF %d\n", val); */
+
+			if (val > sysctl_rmem_max)
 				return -EINVAL;
-			sk->rcvbuf = max(val,256);
+
+			/* FIXME: is this lower bound the right one? */
+			sk->rcvbuf = max(val*2,256);
 			break;
 
 		case SO_KEEPALIVE:
@@ -533,15 +535,29 @@
 }
 
 
+/* FIXME: this is insane. We are trying suppose to be controlling how
+ * how much space we have for data bytes, not packet headers.
+ * This really points out that we need a better system for doing the
+ * receive buffer. -- erics
+ * WARNING: This is currently ONLY used in tcp. If you need it else where
+ * this will probably not be what you want. Possibly these two routines
+ * should move over to the ipv4 directory.
+ */
 unsigned long sock_rspace(struct sock *sk)
 {
 	int amt;
 
-	if (sk != NULL) 
-	{
-		if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*MIN_WINDOW) 
-			return(0);
-		amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2-MIN_WINDOW, MAX_WINDOW);
+	if (sk != NULL) {
+		/* This used to have some bizzare complications that
+		 * to attempt to reserve some amount of space. This doesn't
+	 	 * make sense, since the number returned here does not
+		 * actually reflect allocated space, but rather the amount
+		 * of space we committed to. We gamble that we won't
+		 * run out of memory, and returning a smaller number does
+		 * not change the gamble. If we loose the gamble tcp still
+		 * works, it may just slow down for retransmissions.
+		 */
+		amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);
 		if (amt < 0) 
 			return(0);
 		return(amt);
@@ -550,10 +566,10 @@
 }
 
 
+/* FIXME: this is also insane. See above comment */
 unsigned long sock_wspace(struct sock *sk)
 {
-	if (sk != NULL) 
-	{
+	if (sk != NULL) {
 		if (sk->shutdown & SEND_SHUTDOWN)
 			return(0);
 		if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf)
@@ -868,8 +884,8 @@
 	init_timer(&sk->timer);
 	
 	sk->allocation	=	GFP_KERNEL;
-	sk->rcvbuf	=	SK_RMEM_MAX;
-	sk->sndbuf	=	SK_WMEM_MAX;
+	sk->rcvbuf	=	sysctl_rmem_default*2;
+	sk->sndbuf	=	sysctl_wmem_default*2;
 	sk->priority	=	SOPRI_NORMAL;
 	sk->state 	= 	TCP_CLOSE;
 	sk->zapped	=	1;
diff -u --recursive --new-file v2.1.36/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c
--- v2.1.36/linux/net/core/sysctl_net_core.c	Mon Apr  1 22:03:35 1996
+++ linux/net/core/sysctl_net_core.c	Mon May 12 10:35:44 1997
@@ -8,6 +8,23 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
+extern __u32 sysctl_wmem_default;
+extern __u32 sysctl_rmem_default;
+
 ctl_table core_table[] = {
-	{0}
+	{NET_CORE_WMEM_MAX, "wmem_max",
+	 &sysctl_wmem_max, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_CORE_RMEM_MAX, "rmem_max",
+	 &sysctl_rmem_max, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_CORE_WMEM_DEFAULT, "wmem_default",
+	 &sysctl_wmem_default, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_CORE_RMEM_DEFAULT, "rmem_default",
+	 &sysctl_rmem_default, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{ 0 }
 };
diff -u --recursive --new-file v2.1.36/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.1.36/linux/net/ethernet/eth.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ethernet/eth.c	Mon May 12 10:35:44 1997
@@ -36,8 +36,6 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  */
-#include <asm/uaccess.h>
-#include <asm/system.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -52,16 +50,17 @@
 #include <linux/skbuff.h>
 #include <linux/errno.h>
 #include <linux/config.h>
+#include <linux/init.h>
 #include <net/dst.h>
 #include <net/arp.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
-
-
+#include <asm/uaccess.h>
+#include <asm/system.h>
 #include <asm/checksum.h>
 
 
-void eth_setup(char *str, int *ints)
+__initfunc(void eth_setup(char *str, int *ints))
 {
 	struct device *d = dev_base;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.36/linux/net/ipv4/af_inet.c	Mon Apr 14 16:28:27 1997
+++ linux/net/ipv4/af_inet.c	Mon May 12 10:35:44 1997
@@ -76,6 +76,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -1063,7 +1064,7 @@
  *	Called by socket.c on kernel startup.  
  */
  
-void inet_proto_init(struct net_proto *pro)
+__initfunc(void inet_proto_init(struct net_proto *pro))
 {
 	struct sk_buff *dummy_skb;
 	struct inet_protocol *p;
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.36/linux/net/ipv4/arp.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/arp.c	Mon May 12 10:35:44 1997
@@ -90,6 +90,7 @@
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -1976,7 +1977,7 @@
 };
 #endif
 
-void arp_init (void)
+__initfunc(void arp_init (void))
 {
 	dev_add_pack(&arp_packet_type);
 	/* Start with the regular checks for expired arp entries. */
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.36/linux/net/ipv4/fib.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/fib.c	Mon May 12 10:35:44 1997
@@ -42,6 +42,7 @@
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -2020,7 +2021,7 @@
 }
 
 
-void ip_fib_init()
+__initfunc(void ip_fib_init(void))
 {
 	struct in_rtrulemsg r;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.36/linux/net/ipv4/icmp.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/icmp.c	Mon May 12 10:35:44 1997
@@ -256,6 +256,7 @@
 #include <net/sock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
+#include <linux/init.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <net/checksum.h>
@@ -373,7 +374,7 @@
 
 #ifndef CONFIG_NO_ICMP_LIMIT
 
-static void xrlim_init(void)
+__initfunc(static void xrlim_init(void))
 {
 	int type, entry;
 	struct icmp_xrlim *xr;
@@ -1167,7 +1168,7 @@
  { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_address_reply, 0, NULL }
 };
 
-void icmp_init(struct net_proto_family *ops)
+__initfunc(void icmp_init(struct net_proto_family *ops))
 {
 	int err;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_alias.c linux/net/ipv4/ip_alias.c
--- v2.1.36/linux/net/ipv4/ip_alias.c	Thu Dec 12 06:54:23 1996
+++ linux/net/ipv4/ip_alias.c	Mon May 12 10:35:44 1997
@@ -26,6 +26,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/route.h>
+#include <linux/init.h>
 #include <net/route.h>
 
 #ifdef ALIAS_USER_LAND_DEBUG
@@ -137,7 +138,7 @@
  * ip_alias module initialization
  */
 
-int ip_alias_init(void)
+__initfunc(int ip_alias_init(void))
 {
 	return register_net_alias_type(&ip_alias_type, AF_INET);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.36/linux/net/ipv4/ip_fragment.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/ip_fragment.c	Mon May 12 10:35:44 1997
@@ -518,7 +518,7 @@
 	prev = NULL;
 	for(next = qp->fragments; next != NULL; next = next->next)
 	{
-		if (next->offset > offset)
+		if (next->offset >= offset)
 			break;	/* bingo! */
 		prev = next;
 	}
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.1.36/linux/net/ipv4/ip_fw.c	Thu Mar 27 14:40:15 1997
+++ linux/net/ipv4/ip_fw.c	Mon May 12 10:35:44 1997
@@ -107,6 +107,7 @@
 #include <net/netlink.h>
 #include <linux/firewall.h>
 #include <linux/ip_fw.h>
+#include <linux/init.h>
 
 #ifdef CONFIG_IP_MASQUERADE
 #include <net/ip_masq.h>
@@ -1298,7 +1299,7 @@
 #endif
 
 
-void ip_fw_init(void)
+__initfunc(void ip_fw_init(void))
 {
 #ifdef CONFIG_PROC_FS
 #ifdef CONFIG_IP_ACCT
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.1.36/linux/net/ipv4/ip_masq.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_masq.c	Mon May 12 10:35:44 1997
@@ -31,6 +31,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/inet.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -1010,7 +1011,7 @@
 /*
  *	Initialize ip masquerading
  */
-int ip_masq_init(void)
+__initfunc(int ip_masq_init(void))
 {
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&proc_net_ipmsqhst);
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- v2.1.36/linux/net/ipv4/ip_masq_app.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_masq_app.c	Mon May 12 10:35:44 1997
@@ -30,6 +30,7 @@
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/udp.h>
@@ -482,7 +483,7 @@
  *	Initialization routine
  */
 
-int ip_masq_app_init(void)
+__initfunc(int ip_masq_app_init(void))
 {
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&proc_net_ip_masq_app);
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c
--- v2.1.36/linux/net/ipv4/ip_masq_ftp.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_masq_ftp.c	Mon May 12 10:35:44 1997
@@ -28,6 +28,7 @@
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/ip_masq.h>
@@ -187,7 +188,7 @@
  * 	ip_masq_ftp initialization
  */
 
-int ip_masq_ftp_init(void)
+__initfunc(int ip_masq_ftp_init(void))
 {
         return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c
--- v2.1.36/linux/net/ipv4/ip_masq_irc.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_masq_irc.c	Mon May 12 10:35:44 1997
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/ip_masq.h>
@@ -238,7 +239,7 @@
  * 	ip_masq_irc initialization
  */
 
-int ip_masq_irc_init(void)
+__initfunc(int ip_masq_irc_init(void))
 {
         return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq_quake.c linux/net/ipv4/ip_masq_quake.c
--- v2.1.36/linux/net/ipv4/ip_masq_quake.c	Thu Mar 27 14:40:15 1997
+++ linux/net/ipv4/ip_masq_quake.c	Mon May 12 10:35:44 1997
@@ -28,6 +28,7 @@
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/udp.h>
 #include <net/ip_masq.h>
@@ -279,7 +280,7 @@
  * 	ip_masq_quake initialization
  */
 
-int ip_masq_quake_init(void)
+__initfunc(int ip_masq_quake_init(void))
 {
         return (register_ip_masq_app(&ip_masq_quake, IPPROTO_UDP, 26000) +
 		register_ip_masq_app(&ip_masq_quakenew, IPPROTO_UDP, 27000));
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c
--- v2.1.36/linux/net/ipv4/ip_masq_raudio.c	Mon Apr 14 16:28:27 1997
+++ linux/net/ipv4/ip_masq_raudio.c	Mon May 12 10:35:44 1997
@@ -2,7 +2,7 @@
  *		IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_raudio.c,v 1.5 1997/04/03 08:52:02 davem Exp $
+ * Version:	@(#)$Id: ip_masq_raudio.c,v 1.6 1997/04/29 09:38:26 mj Exp $
  *
  * Author:	Nigel Metheringham
  *		[strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
@@ -45,6 +45,7 @@
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/init.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
 #include <net/ip_masq.h>
@@ -200,7 +201,7 @@
  * 	ip_masq_raudio initialization
  */
 
-int ip_masq_raudio_init(void)
+__initfunc(int ip_masq_raudio_init(void))
 {
         return register_ip_masq_app(&ip_masq_raudio, IPPROTO_TCP, 7070);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.1.36/linux/net/ipv4/ip_output.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_output.c	Mon May 12 10:35:44 1997
@@ -27,6 +27,8 @@
  *					(in case if packet not accepted by
  *					output firewall rules)
  *		Alexey Kuznetsov:	use new route cache
+ *		Andi Kleen:		Fix broken PMTU recovery and remove
+ *					some redundant tests.
  */
 
 #include <asm/uaccess.h>
@@ -47,6 +49,7 @@
 #include <linux/etherdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 
 #include <net/snmp.h>
 #include <net/ip.h>
@@ -126,9 +129,8 @@
 	iph->ihl      = 5;
 	iph->tos      = sk->ip_tos;
 	iph->frag_off = 0;
-	if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-	    (sk->ip_pmtudisc == IP_PMTUDISC_WANT && 
-	     rt->rt_flags&RTF_NOPMTUDISC))
+	if (sk->ip_pmtudisc == IP_PMTUDISC_WANT && 
+		!(rt->rt_flags & RTF_NOPMTUDISC))
 		iph->frag_off |= htons(IP_DF);
 	iph->ttl      = sk->ip_ttl;
 	iph->daddr    = rt->rt_dst;
@@ -207,9 +209,8 @@
 	iph->ihl      = 5;
 	iph->tos      = sk->ip_tos;
 	iph->frag_off = 0;
-	if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-	    (sk->ip_pmtudisc == IP_PMTUDISC_WANT && 
-	     rt->rt_flags&RTF_NOPMTUDISC))
+	if (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
+		!(rt->rt_flags & RTF_NOPMTUDISC))
 		iph->frag_off |= htons(IP_DF);
 	iph->ttl      = sk->ip_ttl;
 	iph->daddr    = rt->rt_dst;
@@ -480,8 +481,7 @@
 #endif	
 
 	if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-	    (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
-	     rt->rt_flags&RTF_NOPMTUDISC))
+	     rt->rt_flags&RTF_NOPMTUDISC)
 		df = 0;
 
 	 
@@ -1036,7 +1036,7 @@
  *	IP registers the packet type and then calls the subprotocol initialisers
  */
 
-void ip_init(void)
+__initfunc(void ip_init(void))
 {
 	dev_add_pack(&ip_packet_type);
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.1.36/linux/net/ipv4/ipmr.c	Mon Apr 14 16:28:27 1997
+++ linux/net/ipv4/ipmr.c	Mon May 12 10:35:44 1997
@@ -47,6 +47,7 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/mroute.h>
+#include <linux/init.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
@@ -1065,7 +1066,7 @@
  *	Setup for IP multicast routing
  */
  
-void ip_mr_init(void)
+__initfunc(void ip_mr_init(void))
 {
 	printk(KERN_INFO "Linux IP multicast router 0.06.\n");
 	register_netdevice_notifier(&ip_mr_notifier);
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.1.36/linux/net/ipv4/rarp.c	Thu Dec 12 06:54:24 1996
+++ linux/net/ipv4/rarp.c	Mon May 12 10:35:44 1997
@@ -45,6 +45,7 @@
 #include <linux/if_arp.h>
 #include <linux/in.h>
 #include <linux/config.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -553,8 +554,8 @@
 	rarp_get_info
 };
 
-void
-rarp_init(void)
+__initfunc(void
+rarp_init(void))
 {
 	proc_net_register(&proc_net_rarp);
 	rarp_ioctl_hook = rarp_ioctl;
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.36/linux/net/ipv4/route.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/route.c	Mon May 12 10:35:44 1997
@@ -69,6 +69,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/route.h>
@@ -1379,7 +1380,7 @@
 	rt_cache_flush(0);
 }
 
-void ip_rt_init()
+__initfunc(void ip_rt_init(void))
 {
 	ip_fib_init();
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.36/linux/net/ipv4/tcp.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/tcp.c	Mon May 12 10:35:44 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.61 1997/04/22 02:53:10 davem Exp $
+ * Version:	$Id: tcp.c,v 1.63 1997/04/29 09:38:33 mj Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -424,6 +424,7 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
+#include <linux/init.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -849,7 +850,6 @@
 				tcp_size = skb->tail -
 					((unsigned char *)(skb->h.th) + tp->tcp_header_len);
 
-				/* printk("extending buffer\n"); */
 				/* This window_seq test is somewhat dangerous
 				 * If the remote does SWS avoidance we should
 				 * queue the best we can if not we should in 
@@ -1100,6 +1100,9 @@
 		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 		__u32 rcv_wnd;
 
+	 	/* FIXME: double check this rule, then check against
+		 * other use of similar rules. Abtract if possible.
+		 */
 		rcv_wnd = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
 
 		if ((rcv_wnd < sk->mss) && (sock_rspace(sk) > rcv_wnd))
@@ -1655,7 +1658,7 @@
 		tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
 }
 
-void tcp_init(void)
+__initfunc(void tcp_init(void))
 {
 	tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
 					       sizeof(struct open_request),
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.36/linux/net/ipv4/tcp_input.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv4/tcp_input.c	Mon May 12 10:35:44 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.50 1997/04/22 02:53:12 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.51 1997/04/27 19:24:40 schenk Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -321,8 +321,10 @@
 	  					break;
 					case TCPOPT_WINDOW:
 	  					if(opsize==TCPOLEN_WINDOW && th->syn)
-							if (sysctl_tcp_window_scaling)
+							if (sysctl_tcp_window_scaling) {
+								tp->wscale_ok = 1;
 								tp->snd_wscale = *(__u8 *)ptr;
+							}
 						break;
 					case TCPOPT_SACK_PERM:
 	  					if(opsize==TCPOLEN_SACK_PERM && th->syn)
@@ -816,7 +818,7 @@
 	 */
 	if (before(tp->snd_wl1, ack_seq) ||
 	    (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
-		unsigned long nwin = ntohs(th->window);
+		unsigned long nwin = ntohs(th->window) << tp->snd_wscale;
 
 		if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
 			flag |= FLAG_WIN_UPDATE;
@@ -1464,17 +1466,21 @@
 			if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
 				return 1;
 
-			/*  Now we have several options: In theory there is 
-			 *  nothing else in the frame. KA9Q has an option to 
-			 *  send data with the syn, BSD accepts data with the
-			 *  syn up to the [to be] advertised window and 
-			 *  Solaris 2.1 gives you a protocol error. For now 
-			 *  we just ignore it, that fits the spec precisely 
-			 *  and avoids incompatibilities. It would be nice in
-			 *  future to drop through and process the data.
+			/* Now we have several options: In theory there is 
+			 * nothing else in the frame. KA9Q has an option to 
+			 * send data with the syn, BSD accepts data with the
+			 * syn up to the [to be] advertised window and 
+			 * Solaris 2.1 gives you a protocol error. For now 
+			 * we just ignore it, that fits the spec precisely 
+			 * and avoids incompatibilities. It would be nice in
+			 * future to drop through and process the data.
 			 *
-			 *  Now that TTCP is starting to be used we ought to 
-			 *  queue this data.
+			 * Now that TTCP is starting to be used we ought to 
+			 * queue this data.
+			 * But, this leaves one open to an easy denial of
+		 	 * service attack, and SYN cookies can't defend
+			 * against this problem. So, we drop the data
+			 * in the interest of security over speed.
 			 */
 			return 0;
 		}
@@ -1514,10 +1520,9 @@
 			 * move to established.
 			 */
 			tp->rcv_nxt = skb->seq+1;
-			tp->rcv_wnd = 0;
 			tp->rcv_wup = skb->seq+1;
 
-			tp->snd_wnd = htons(th->window);
+			tp->snd_wnd = htons(th->window) << tp->snd_wscale;
 			tp->snd_wl1 = skb->seq;
 			tp->snd_wl2 = skb->ack_seq;
 
@@ -1526,6 +1531,10 @@
 			tcp_set_state(sk, TCP_ESTABLISHED);
 			tcp_parse_options(th,tp);
 			/* FIXME: need to make room for SACK still */
+        		if (tp->wscale_ok == 0) {
+                		tp->snd_wscale = tp->rcv_wscale = 0;
+                		tp->window_clamp = min(tp->window_clamp,65535);
+        		}
 			if (tp->tstamp_ok) {
 				tp->tcp_header_len = sizeof(struct tcphdr) + 12;	/* FIXME: Define constant! */
 				sk->dummy_th.doff += 3;		/* reserve space of options */
@@ -1695,7 +1704,7 @@
 					sk->state_change(sk);		
 
 				tp->snd_una = skb->ack_seq;
-				tp->snd_wnd = htons(th->window);
+				tp->snd_wnd = htons(th->window) << tp->snd_wscale;
 				tp->snd_wl1 = skb->seq;
 				tp->snd_wl2 = skb->ack_seq;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.36/linux/net/ipv4/tcp_ipv4.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv4/tcp_ipv4.c	Mon May 12 10:35:44 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.39 1997/04/22 02:53:14 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.42 1997/04/29 16:09:46 schenk Exp $
  *
  *		IPv4 specific functions
  *
@@ -465,7 +465,7 @@
 	struct sk_buff *buff;
 	struct sk_buff *skb1;
 	int tmp;
-	struct tcphdr *t1;
+	struct tcphdr *th;
 	struct rtable *rt;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
@@ -546,20 +546,17 @@
 		return(-ENETUNREACH);
 	}
 
-	t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
-	buff->h.th = t1;
+	th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
+	buff->h.th = th;
 
-	memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
+	memcpy(th,(void *)&(sk->dummy_th), sizeof(*th));
 	buff->seq = sk->write_seq++;
-	t1->seq = htonl(buff->seq);
+	th->seq = htonl(buff->seq);
 	tp->snd_nxt = sk->write_seq;
 	buff->end_seq = sk->write_seq;
-	t1->ack = 0;
-	t1->window = htons(512);
-	t1->syn = 1;
+	th->ack = 0;
+	th->syn = 1;
 
-	/* Use 512 or whatever user asked for. */
-	tp->window_clamp = rt->u.dst.window;
 
 	sk->mtu = rt->u.dst.pmtu;
 	if ((sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
@@ -577,13 +574,26 @@
 		sk->mss = (sk->mtu - sizeof(struct iphdr) -
 			   sizeof(struct tcphdr));
 
+	if (sk->mss < 1) {
+		printk(KERN_DEBUG "intial sk->mss below 1\n");
+		sk->mss = 1;	/* Sanity limit */
+	}
+
+	tp->window_clamp = rt->u.dst.window;
+	tcp_select_initial_window(sock_rspace(sk)/2,sk->mss,
+		&tp->rcv_wnd,
+		&tp->window_clamp,
+		sysctl_tcp_window_scaling,
+		&tp->rcv_wscale);
+	th->window = htons(tp->rcv_wnd);
+
 	tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
 		sysctl_tcp_timestamps,
-		sysctl_tcp_window_scaling?tp->rcv_wscale:0);
+		sysctl_tcp_window_scaling,tp->rcv_wscale);
 	buff->csum = 0;
-	t1->doff = (sizeof(*t1)+ tmp)>>2;
+	th->doff = (sizeof(*th)+ tmp)>>2;
 
-	tcp_v4_send_check(sk, t1, sizeof(struct tcphdr) + tmp, buff);
+	tcp_v4_send_check(sk, th, sizeof(struct tcphdr) + tmp, buff);
 
 	tcp_set_state(sk,TCP_SYN_SENT);
 
@@ -803,7 +813,6 @@
 
 static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
 {
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	struct sk_buff * skb;
 	struct tcphdr *th;
 	int tmp;
@@ -829,6 +838,11 @@
 	 */
 	req->mss = min(mss, req->mss);
 
+	if (req->mss < 1) {
+		printk(KERN_DEBUG "initial req->mss below 1\n");
+		req->mss = 1;
+	}
+
 	/* Yuck, make this header setup more efficient... -DaveM */
 	memset(th, 0, sizeof(struct tcphdr));
 	th->syn = 1;
@@ -839,7 +853,16 @@
 	skb->end_seq = skb->seq + 1;
 	th->seq = ntohl(skb->seq);
 	th->ack_seq = htonl(req->rcv_isn + 1);
-	th->window = ntohs(tp->rcv_wnd);
+	if (req->rcv_wnd == 0) {
+		/* Set this up on the first call only */
+		req->window_clamp = skb->dst->window;
+		tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+			&req->rcv_wnd,
+			&req->window_clamp,
+			req->wscale_ok,
+			&req->rcv_wscale);
+	}
+	th->window = htons(req->rcv_wnd);
 
 	/* XXX Partial csum of 4 byte quantity is itself! -DaveM
 	 * Yes, but it's a bit harder to special case now. It's
@@ -850,7 +873,7 @@
 	 */
 
 	tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
-		(req->snd_wscale)?tp->rcv_wscale:0);
+		req->wscale_ok,req->rcv_wscale);
 	skb->csum = 0;
 	th->doff = (sizeof(*th) + tmp)>>2;
 	th->check = tcp_v4_check(th, sizeof(*th) + tmp,
@@ -881,7 +904,7 @@
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn)
 {
 	struct ip_options *opt = (struct ip_options *) ptr;
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct tcp_opt tp;
 	struct open_request *req;
 	struct tcphdr *th = skb->h.th;
 	__u32 saddr = skb->nh.iph->saddr;
@@ -913,19 +936,20 @@
 
 	sk->ack_backlog++;
 
+	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
+
 	req->rcv_isn = skb->seq;
 	req->snt_isn = isn;
-	tp->tstamp_ok = tp->sack_ok = tp->snd_wscale = 0;
-	tcp_parse_options(th,tp);
-	if (tp->saw_tstamp) {
-		tp->ts_recent = tp->rcv_tsval;
-		tp->ts_recent_stamp = jiffies;
-	}
-	req->mss = tp->in_mss;
-	req->tstamp_ok = tp->tstamp_ok;
-	req->sack_ok = tp->sack_ok;
-	req->snd_wscale = tp->snd_wscale;
-	req->ts_recent = tp->ts_recent;
+	tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+	tp.in_mss = 536;
+	tcp_parse_options(th,&tp);
+	if (tp.saw_tstamp)
+		req->ts_recent = tp.rcv_tsval;
+	req->mss = tp.in_mss;
+	req->tstamp_ok = tp.tstamp_ok;
+	req->sack_ok = tp.sack_ok;
+	req->snd_wscale = tp.snd_wscale;
+	req->wscale_ok = tp.wscale_ok;
 	req->rmt_port = th->source;
 	req->af.v4_req.loc_addr = daddr;
 	req->af.v4_req.rmt_addr = saddr;
@@ -1004,8 +1028,6 @@
 	atomic_set(&newsk->rmem_alloc, 0);
 	newsk->localroute = sk->localroute;
 
-	newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
-
 	newsk->err = 0;
 	newsk->shutdown = 0;
 	newsk->ack_backlog = 0;
@@ -1060,7 +1082,6 @@
 
 	newsk->dst_cache = &rt->u.dst;
 
-	newtp->window_clamp = rt->u.dst.window;
 	snd_mss = rt->u.dst.pmtu;
 
 	/* FIXME: is mtu really the same as snd_mss? */
@@ -1072,10 +1093,19 @@
 
 	newtp->sack_ok = req->sack_ok;
 	newtp->tstamp_ok = req->tstamp_ok;
-	newtp->snd_wscale = req->snd_wscale;
-	newtp->ts_recent = req->ts_recent;
-	newtp->ts_recent_stamp = jiffies;
+	newtp->window_clamp = req->window_clamp;
+	newtp->rcv_wnd = req->rcv_wnd;
+	newtp->wscale_ok = req->wscale_ok;
+	if (newtp->wscale_ok) {
+		newtp->snd_wscale = req->snd_wscale;
+		newtp->rcv_wscale = req->rcv_wscale;
+	} else {
+		newtp->snd_wscale = newtp->rcv_wscale = 0;
+		newtp->window_clamp = min(newtp->window_clamp,65535);
+	}
 	if (newtp->tstamp_ok) {
+		newtp->ts_recent = req->ts_recent;
+		newtp->ts_recent_stamp = jiffies;
 		newtp->tcp_header_len = sizeof(struct tcphdr) + 12;	/* FIXME: define constant! */
 		newsk->dummy_th.doff += 3;
 	} else {
@@ -1219,9 +1249,8 @@
 	case CHECKSUM_HW:
 		if (tcp_v4_check(th,len,saddr,daddr,skb->csum)) {
 			struct iphdr * iph = skb->nh.iph;
-			printk(KERN_DEBUG "TCPv4 bad checksum from %08x:%04x to %08x:%04x, ack = %u, seq = %u, len=%d/%d/%d\n",
+			printk(KERN_DEBUG "TCPv4 bad checksum from %08x:%04x to %08x:%04x, len=%d/%d/%d\n",
 			       saddr, ntohs(th->source), daddr,
-			       ntohl(th->ack_seq), ntohl(th->seq),
 			       ntohs(th->dest), len, skb->len, ntohs(iph->tot_len));
 					goto discard_it;
 		}
@@ -1346,10 +1375,12 @@
 	tp->ato = 0;
 	tp->iat = (HZ/5) << 3;
 
-	tp->rcv_wnd = 8192;
+	/* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */
+	/* tp->rcv_wnd = 8192; */
 	tp->tstamp_ok = 0;
 	tp->sack_ok = 0;
-	tp->in_mss = 0;
+	tp->wscale_ok = 0;
+	tp->in_mss = 536;
 	tp->snd_wscale = 0;
 	tp->sacks = 0;
 	tp->saw_tstamp = 0;
diff -u --recursive --new-file v2.1.36/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.36/linux/net/ipv4/tcp_output.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv4/tcp_output.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.42 1997/04/22 01:06:33 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.43 1997/04/27 19:24:43 schenk Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -404,14 +404,115 @@
 
 
 
-/*
- *      This function returns the amount that we can raise the
- *      usable window based on the following constraints
+/* This function returns the amount that we can raise the
+ * usable window based on the following constraints
  *  
- *	1. The window can never be shrunk once it is offered (RFC 793)
- *	2. We limit memory per socket
+ * 1. The window can never be shrunk once it is offered (RFC 793)
+ * 2. We limit memory per socket
+ *
+ * RFC 1122:
+ * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+ *  RECV.NEXT + RCV.WIN fixed until:
+ *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+ *
+ * i.e. don't raise the right edge of the window until you can raise
+ * it at least MSS bytes.
+ *
+ * Unfortunately, the recomended algorithm breaks header prediction,
+ * since header prediction assumes th->window stays fixed.
+ *
+ * Strictly speaking, keeping th->window fixed violates the receiver
+ * side SWS prevention criteria. The problem is that under this rule
+ * a stream of single byte packets will cause the right side of the
+ * window to always advance by a single byte.
+ * 
+ * Of course, if the sender implements sender side SWS prevention
+ * then this will not be a problem.
+ * 
+ * BSD seems to make the following compromise:
+ * 
+ *	If the free space is less than the 1/4 of the maximum
+ *	space available and the free space is less than 1/2 mss,
+ *	then set the window to 0.
+ *	Otherwise, just prevent the window from shrinking
+ *	and from being larger than the largest representable value.
+ *
+ * This prevents incremental opening of the window in the regime
+ * where TCP is limited by the speed of the reader side taking
+ * data out of the TCP receive queue. It does nothing about
+ * those cases where the window is constrained on the sender side
+ * because the pipeline is full.
+ *
+ * BSD also seems to "accidentally" limit itself to windows that are a
+ * multiple of MSS, at least until the free space gets quite small.
+ * This would appear to be a side effect of the mbuf implementation.
+ * Combining these two algorithms results in the observed behavior
+ * of having a fixed window size at almost all times.
+ *
+ * Below we obtain similar behavior by forcing the offered window to
+ * a multiple of the mss when it is feasible to do so.
+ *
+ * FIXME: In our current implementation the value returned by sock_rpsace(sk)
+ * is the total space we have allocated to the socket to store skbuf's.
+ * The current design assumes that up to half of that space will be
+ * taken by headers, and the remaining space will be available for TCP data.
+ * This should be accounted for correctly instead.
  */
+unsigned short tcp_select_window(struct sock *sk)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	int mss = sk->mss;
+	long free_space = sock_rspace(sk)/2;
+	long window, cur_win;
+
+	if (tp->window_clamp) {
+		free_space = min(tp->window_clamp, free_space);
+		mss = min(tp->window_clamp, mss);
+	} else
+		printk(KERN_DEBUG "Clamp failure. Water leaking.\n");
+
+	if (mss < 1) {
+		mss = 1;
+		printk(KERN_DEBUG "tcp_select_window: mss fell to 0.\n");
+	}
+	
+	/* compute the actual window i.e.
+	 * old_window - received_bytes_on_that_win
+	 */
+	cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
+	window  = tp->rcv_wnd;
+
+	if (cur_win < 0) {
+		cur_win = 0;
+		printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
+		       tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
+	}
+
+	if (free_space < sk->rcvbuf/4 && free_space < mss/2)
+		window = 0;
+
+	/* Get the largest window that is a nice multiple of mss.
+	 * Window clamp already applied above.
+	 * If our current window offering is within 1 mss of the
+	 * free space we just keep it. This prevents the divide
+	 * and multiply from happening most of the time.
+	 * We also don't do any window rounding when the free space
+	 * is too small.
+	 */
+	if (window < free_space - mss && free_space > mss)
+		window = (free_space/mss)*mss;
 
+	/* Never shrink the offered window */
+	if (window < cur_win)
+		window = cur_win;
+
+	tp->rcv_wnd = window;
+	tp->rcv_wup = tp->rcv_nxt;
+	return window >> tp->rcv_wscale;	/* RFC1323 scaling applied */
+}
+
+#if 0
+/* Old algorithm for window selection */
 unsigned short tcp_select_window(struct sock *sk)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -427,37 +528,31 @@
 	/* compute the actual window i.e.
 	 * old_window - received_bytes_on_that_win
 	 */
-	cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+	cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
 	window  = tp->rcv_wnd;
-	
+
 	if (cur_win < 0) {
 		cur_win = 0;
 		printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
 		       tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
 	}
 
-	/*
-	 * RFC 1122:
+	/* RFC 1122:
 	 * "the suggested [SWS] avoidance algoritm for the receiver is to keep
 	 *  RECV.NEXT + RCV.WIN fixed until:
 	 *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
 	 *
-	 * i.e. don't raise the right edge of the window until you can't raise
-	 * it MSS bytes
+	 * i.e. don't raise the right edge of the window until you can raise
+	 * it at least MSS bytes.
 	 */
 
-	/* It would be a good idea if it didn't break header prediction.
-	 * and BSD made the header predition standard...
-	 * It expects the same value in the header i.e. th->window to be
-	 * constant
-	 */
 	usable = free_space - cur_win;
 	if (usable < 0)
 		usable = 0;
 
 	if (window < usable) {
 		/*	Window is not blocking the sender
-		 *	and we have enought free space for it
+		 *	and we have enough free space for it
 		 */
 		if (cur_win > (sk->mss << 1))
 			goto out;
@@ -469,7 +564,7 @@
 		 */
 		window = max(usable, cur_win);
 	} else {
-		if ((usable - window) >= mss)
+		while ((usable - window) >= mss)
 			window += mss;
 	}
 out:
@@ -477,6 +572,7 @@
 	tp->rcv_wup = tp->rcv_nxt;
 	return window;
 }
+#endif
 
 static int tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb)
 {
@@ -703,6 +799,11 @@
 	}
 }
 
+/* WARNING: This routine must only be called when we have already sent
+ * a SYN packet that crossed the incoming SYN that caused this routine
+ * to get called. If this assumption fails then the initial rcv_wnd
+ * and rcv_wscale values will not be correct.
+ */
 int tcp_send_synack(struct sock *sk)
 {
 	struct tcp_opt * tp = &(sk->tp_pinfo.af_tcp);
@@ -735,13 +836,16 @@
 	skb->end_seq = skb->seq + 1 /* th->syn */ ;
 	th->seq = ntohl(skb->seq);
 
-	th->window = ntohs(tp->rcv_wnd);
+	/* This is a resend of a previous SYN, now with an ACK.
+	 * we must reuse the previously offered window.
+	 */
+	th->window = htons(tp->rcv_wnd);
 
 	tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
 
 	tmp = tcp_syn_build_options(skb, sk->mss,
 		tp->sack_ok, tp->tstamp_ok,
-		tp->snd_wscale?tp->rcv_wscale:0);
+		tp->wscale_ok,tp->rcv_wscale);
 	skb->csum = 0;
 	th->doff = (sizeof(*th) + tmp)>>2;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.36/linux/net/ipv6/addrconf.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv6/addrconf.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: addrconf.c,v 1.18 1997/04/16 05:58:03 davem Exp $
+ *	$Id: addrconf.c,v 1.19 1997/04/29 09:38:41 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/route.h>
+#include <linux/init.h>
 
 #include <linux/proc_fs.h>
 #include <net/sock.h>
@@ -1215,7 +1216,7 @@
  *	Init / cleanup code
  */
 
-void addrconf_init()
+__initfunc(void addrconf_init(void))
 {
 	struct device *dev;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.36/linux/net/ipv6/af_inet6.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/af_inet6.c	Mon May 12 10:35:45 1997
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.16 1997/03/18 18:24:26 davem Exp $
+ *	$Id: af_inet6.c,v 1.17 1997/04/29 09:38:39 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -459,7 +460,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-void inet6_proto_init(struct net_proto *pro)
+__initfunc(void inet6_proto_init(struct net_proto *pro))
 #endif
 {
 	struct sk_buff *dummy_skb;
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c
--- v2.1.36/linux/net/ipv6/datagram.c	Mon Apr 14 16:28:28 1997
+++ linux/net/ipv6/datagram.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: datagram.c,v 1.10 1997/04/14 05:39:42 davem Exp $
+ *	$Id: datagram.c,v 1.11 1997/05/03 00:58:25 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -15,6 +15,9 @@
 
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/in6.h>
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.1.36/linux/net/ipv6/icmp.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/icmp.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: icmp.c,v 1.8 1997/03/18 18:24:30 davem Exp $
+ *	$Id: icmp.c,v 1.9 1997/04/29 09:38:42 mj Exp $
  *
  *	Based on net/ipv4/icmp.c
  *
@@ -34,6 +34,7 @@
 #include <linux/sockios.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -486,7 +487,7 @@
 	return 0;
 }
 
-void icmpv6_init(struct net_proto_family *ops)
+__initfunc(void icmpv6_init(struct net_proto_family *ops))
 {
 	struct sock *sk;
 	int err;
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- v2.1.36/linux/net/ipv6/ip6_fw.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/ip6_fw.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fw.c,v 1.4 1997/03/18 18:24:34 davem Exp $
+ *	$Id: ip6_fw.c,v 1.5 1997/04/29 09:38:44 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -22,6 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/in6.h>
 #include <linux/udp.h>
+#include <linux/init.h>
 
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
@@ -365,7 +366,7 @@
 #define ip6_fw_init module_init
 #endif
 
-void ip6_fw_init(void)
+__initfunc(void ip6_fw_init(void))
 {
 	netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.1.36/linux/net/ipv6/ipv6_sockglue.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv6/ipv6_sockglue.c	Mon May 12 10:35:45 1997
@@ -7,7 +7,7 @@
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
- *	$Id: ipv6_sockglue.c,v 1.11 1997/04/20 09:44:33 davem Exp $
+ *	$Id: ipv6_sockglue.c,v 1.12 1997/04/29 09:38:45 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -31,12 +31,11 @@
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-
+#include <linux/init.h>
 #include <linux/sysctl.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
-
 #include <net/ipv6.h>
 #include <net/ndisc.h>
 #include <net/protocol.h>
@@ -239,7 +238,7 @@
 extern void ipv6_sysctl_unregister(void);
 #endif
 
-void ipv6_init(void)
+__initfunc(void ipv6_init(void))
 {
 	dev_add_pack(&ipv6_packet_type);
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- v2.1.36/linux/net/ipv6/mcast.c	Mon Apr 14 16:28:28 1997
+++ linux/net/ipv6/mcast.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: mcast.c,v 1.8 1997/04/12 04:32:48 davem Exp $
+ *	$Id: mcast.c,v 1.9 1997/04/29 09:38:46 mj Exp $
  *
  *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
  *
@@ -27,6 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/route.h>
+#include <linux/init.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -495,7 +496,7 @@
 	ma->mca_flags &= ~MAF_TIMER_RUNNING;
 }
 
-void igmp6_init(struct net_proto_family *ops)
+__initfunc(void igmp6_init(struct net_proto_family *ops))
 {
 	struct sock *sk;
 	int err;
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.1.36/linux/net/ipv6/ndisc.c	Mon Apr 14 16:28:28 1997
+++ linux/net/ipv6/ndisc.c	Mon May 12 10:35:45 1997
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Mike Shaver		<shaver@ingenia.com>
  *
- *	$Id: ndisc.c,v 1.14 1997/04/12 04:32:51 davem Exp $
+ *	$Id: ndisc.c,v 1.15 1997/04/29 09:38:48 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -43,6 +43,7 @@
 #include <linux/net.h>
 #include <linux/in6.h>
 #include <linux/route.h>
+#include <linux/init.h>
 
 #include <linux/if_arp.h>
 #include <linux/ipv6.h>
@@ -1647,7 +1648,7 @@
 };
 #endif	/* CONFIG_PROC_FS */
 
-void ndisc_init(struct net_proto_family *ops)
+__initfunc(void ndisc_init(struct net_proto_family *ops))
 {
 	struct sock *sk;
         int err;
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.1.36/linux/net/ipv6/route.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv6/route.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.11 1997/04/16 05:58:05 davem Exp $
+ *	$Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -22,6 +22,7 @@
 #include <linux/route.h>
 #include <linux/netdevice.h>
 #include <linux/in6.h>
+#include <linux/init.h>
 
 #ifdef 	CONFIG_PROC_FS
 #include <linux/proc_fs.h>
@@ -1573,7 +1574,7 @@
 };
 #endif	/* CONFIG_PROC_FS */
 
-void ip6_route_init(void)
+__initfunc(void ip6_route_init(void))
 {
 #ifdef 	CONFIG_PROC_FS
 	proc_net_register(&proc_rt6_info);
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
--- v2.1.36/linux/net/ipv6/sit.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipv6/sit.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: sit.c,v 1.13 1997/03/18 18:24:50 davem Exp $
+ *	$Id: sit.c,v 1.14 1997/04/29 09:38:52 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -23,6 +23,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/icmp.h>
+#include <linux/init.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -243,7 +244,7 @@
 	return 0;
 }
 
-int sit_init(void)
+__initfunc(int sit_init(void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.36/linux/net/ipv6/tcp_ipv6.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv6/tcp_ipv6.c	Mon May 12 10:35:45 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.27 1997/04/22 02:53:20 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.31 1997/04/29 21:51:23 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -27,6 +27,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/netdevice.h>
+#include <linux/init.h>
 
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
@@ -432,21 +433,32 @@
 	tp->snd_nxt = sk->write_seq;
 	buff->end_seq = sk->write_seq;
 	th->ack = 0;
-	th->window = 2;
 	th->syn = 1;
 
-	tp->window_clamp = 0;
 
 	sk->mtu = dst->pmtu;
 	sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
 
+        if (sk->mss < 1) {
+                printk(KERN_DEBUG "intial ipv6 sk->mss below 1\n");
+                sk->mss = 1;    /* Sanity limit */
+        }
+
+	tp->window_clamp = 0;	/* FIXME: shouldn't ipv6 dst cache have this? */
+	tcp_select_initial_window(sock_rspace(sk)/2,sk->mss,
+		&tp->rcv_wnd,
+		&tp->window_clamp,
+		sysctl_tcp_window_scaling,
+		&tp->rcv_wscale);
+	th->window = htons(tp->rcv_wnd);
+
 	/*
 	 *	Put in the TCP options to say MTU.
 	 */
 
         tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
                 sysctl_tcp_timestamps,
-                sysctl_tcp_window_scaling?tp->rcv_wscale:0);
+                sysctl_tcp_window_scaling,tp->rcv_wscale);
         th->doff = sizeof(*th)/4 + (tmp>>2);
 	buff->csum = 0;
 	tcp_v6_send_check(sk, th, sizeof(struct tcphdr) + tmp, buff);
@@ -586,9 +598,11 @@
 }
 
 
+/* FIXME: this is substantially similar to the ipv4 code.
+ * Can some kind of merge be done? -- erics
+ */
 static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
 {
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	struct sk_buff * skb;
 	struct tcphdr *th;
 	struct dst_entry *dst;
@@ -630,11 +644,32 @@
 	th->seq = ntohl(skb->seq);
 	th->ack_seq = htonl(req->rcv_isn + 1);
 	th->doff = sizeof(*th)/4 + 1;
-	
-	th->window = ntohs(tp->rcv_wnd);
 
-	tmp = tcp_syn_build_options(skb, sk->mss, req->sack_ok, req->tstamp_ok,
-		(req->snd_wscale)?tp->rcv_wscale:0);
+	/* Don't offer more than they did.
+	 * This way we don't have to memorize who said what.
+	 * FIXME: the selection of initial mss here doesn't quite
+	 * match what happens under IPV4. Figure out the right thing to do.
+	 */
+        req->mss = min(sk->mss, req->mss);
+
+        if (req->mss < 1) {
+                printk(KERN_DEBUG "initial req->mss below 1\n");
+                req->mss = 1;
+        }
+
+	if (req->rcv_wnd == 0) {
+		/* Set this up on the first call only */
+		req->window_clamp = 0; /* FIXME: should be in dst cache */
+		tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+			&req->rcv_wnd,
+			&req->window_clamp,
+			req->wscale_ok,
+			&req->rcv_wscale);
+	}
+	th->window = htons(req->rcv_wnd);
+
+	tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+		req->snd_wscale,req->rcv_wscale);
 	th->doff = sizeof(*th)/4 + (tmp>>2);
 	th->check = tcp_v6_check(th, sizeof(*th) + tmp,
 				 &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
@@ -656,10 +691,13 @@
 	tcp_v6_or_free
 };
 
+/* FIXME: this is substantially similar to the ipv4 code.
+ * Can some kind of merge be done? -- erics
+ */
 static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 			       __u32 isn)
 {
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct tcp_opt tp;
 	struct open_request *req;
 	__u16 req_mss;
 	
@@ -691,14 +729,20 @@
 
 	sk->ack_backlog++;
 
+	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
+
 	req->rcv_isn = skb->seq;
 	req->snt_isn = isn;
-
-	tcp_parse_options(skb->h.th,tp);
-	req_mss = tp->in_mss;
-	if (!req_mss)
-		req_mss = 536;
-	req->mss = req_mss;
+	tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+	tp.in_mss = 536;
+	tcp_parse_options(skb->h.th,&tp);
+	if (tp.saw_tstamp)
+                req->ts_recent = tp.rcv_tsval;
+        req->mss = tp.in_mss;
+        req->tstamp_ok = tp.tstamp_ok;
+        req->sack_ok = tp.sack_ok;
+        req->snd_wscale = tp.snd_wscale;
+        req->wscale_ok = tp.wscale_ok;
 	req->rmt_port = skb->h.th->source;
 	ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr);
 	ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr);
@@ -876,6 +920,7 @@
         newtp->sack_ok = req->sack_ok;
         newtp->tstamp_ok = req->tstamp_ok;
         newtp->snd_wscale = req->snd_wscale;
+	newtp->wscale_ok = req->wscale_ok;
         newtp->ts_recent = req->ts_recent;
         if (newtp->tstamp_ok) {
                 newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define the contant. */
@@ -1305,8 +1350,11 @@
 
 	tp->ato = 0;
 	tp->iat = (HZ/5) << 3;
-
-	tp->rcv_wnd = 8192;
+	
+	/* FIXME: right thing? */
+	tp->rcv_wnd = 0;
+	tp->in_mss = 536;
+	/* tp->rcv_wnd = 8192; */
 
 	/* start with only sending one packet at a time. */
 	tp->snd_cwnd = 1;
@@ -1320,7 +1368,7 @@
 	sk->max_ack_backlog = SOMAXCONN;
 
 	sk->mtu = 576;
-	sk->mss = 516;
+	sk->mss = 536;
 
 	sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
 
@@ -1416,7 +1464,7 @@
 	"TCPv6"			/* name			*/
 };
 
-void tcpv6_init(void)
+__initfunc(void tcpv6_init(void))
 {
 	/* register inet6 protocol */
 	inet6_add_protocol(&tcpv6_protocol);
diff -u --recursive --new-file v2.1.36/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.36/linux/net/ipv6/udp.c	Mon Apr 14 16:28:28 1997
+++ linux/net/ipv6/udp.c	Mon May 12 10:35:45 1997
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.16 1997/04/11 22:22:57 davem Exp $
+ *	$Id: udp.c,v 1.17 1997/04/29 09:38:55 mj Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@
 #include <linux/if_arp.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/init.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -770,7 +771,7 @@
 	0				/* highestinuse */
 };
 
-void udpv6_init(void)
+__initfunc(void udpv6_init(void))
 {
 	inet6_add_protocol(&udpv6_protocol);
 }
diff -u --recursive --new-file v2.1.36/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.36/linux/net/ipx/af_ipx.c	Mon Apr 14 16:28:28 1997
+++ linux/net/ipx/af_ipx.c	Mon May 12 10:35:45 1997
@@ -91,6 +91,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/firewall.h>
+#include <linux/init.h>
 
 #ifdef MODULE
 static void ipx_proto_finito(void);
@@ -2434,7 +2435,7 @@
  * sockets be closed from user space.
  */
 
-static void ipx_proto_finito(void)
+__initfunc(static void ipx_proto_finito(void))
 {	ipx_interface	*ifc;
 
 	while (ipx_interfaces) {
diff -u --recursive --new-file v2.1.36/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.1.36/linux/net/lapb/lapb_iface.c	Thu Feb 27 10:57:32 1997
+++ linux/net/lapb/lapb_iface.c	Mon May 12 10:35:45 1997
@@ -39,6 +39,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/stat.h>
+#include <linux/init.h>
 #include <net/lapb.h>
 
 static lapb_cb *volatile lapb_list = NULL;
@@ -397,7 +398,7 @@
 EXPORT_SYMBOL(lapb_data_request);
 EXPORT_SYMBOL(lapb_data_received);
 
-void lapb_proto_init(struct net_proto *pro)
+__initfunc(void lapb_proto_init(struct net_proto *pro))
 {
 	printk(KERN_INFO "LAPB for Linux. Version 0.01 for Linux NET3.038 (Linux 2.1)\n");
 }
diff -u --recursive --new-file v2.1.36/linux/net/netbeui/af_netbeui.c linux/net/netbeui/af_netbeui.c
--- v2.1.36/linux/net/netbeui/af_netbeui.c	Mon Apr 14 16:28:28 1997
+++ linux/net/netbeui/af_netbeui.c	Mon May 12 10:35:45 1997
@@ -31,6 +31,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/firewall.h>
+#include <linux/init.h>
 
 
 #undef NETBEUI_DEBUG
@@ -620,7 +621,7 @@
 
 /* Called by proto.c on kernel start up */
 
-void netbeui_proto_init(struct net_proto *pro)
+__initfunc(void netbeui_proto_init(struct net_proto *pro))
 {
 	(void) sock_register(netbeui_proto_ops.family, &netbeui_proto_ops);
 	if ((nb_dl = register_8022_client(nb_8022_id, netbeui_rcv)) == NULL)
diff -u --recursive --new-file v2.1.36/linux/net/netlink.c linux/net/netlink.c
--- v2.1.36/linux/net/netlink.c	Fri Apr  4 08:52:29 1997
+++ linux/net/netlink.c	Mon May 12 10:35:45 1997
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 
 #include <net/netlink.h>
 
@@ -443,7 +444,7 @@
 }
 
 
-int init_netlink(void)
+__initfunc(int init_netlink(void))
 {
 	int ct;
 
diff -u --recursive --new-file v2.1.36/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.36/linux/net/netrom/af_netrom.c	Mon Apr 14 16:28:28 1997
+++ linux/net/netrom/af_netrom.c	Mon May 12 10:35:45 1997
@@ -64,6 +64,7 @@
 #include <net/ip.h>
 #include <net/arp.h>
 #include <linux/if_arp.h>
+#include <linux/init.h>
 
 int sysctl_netrom_default_path_quality            = NR_DEFAULT_QUAL;
 int sysctl_netrom_obsolescence_count_initialiser  = NR_DEFAULT_OBS;
@@ -1361,7 +1362,7 @@
 	{"nr3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}
 };
 
-void nr_proto_init(struct net_proto *pro)
+__initfunc(void nr_proto_init(struct net_proto *pro))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/net/netrom/sysctl_net_netrom.c linux/net/netrom/sysctl_net_netrom.c
--- v2.1.36/linux/net/netrom/sysctl_net_netrom.c	Sun Feb  2 05:18:52 1997
+++ linux/net/netrom/sysctl_net_netrom.c	Mon May 12 10:35:45 1997
@@ -7,6 +7,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/init.h>
 #include <net/ax25.h>
 #include <net/netrom.h>
 
@@ -78,7 +79,7 @@
 	{0}
 };
 
-void nr_register_sysctl(void)
+__initfunc(void nr_register_sysctl(void))
 {
 	nr_table_header = register_sysctl_table(nr_root_table, 1);
 }
diff -u --recursive --new-file v2.1.36/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.36/linux/net/netsyms.c	Mon Apr 14 16:28:28 1997
+++ linux/net/netsyms.c	Mon May 12 10:35:45 1997
@@ -200,6 +200,10 @@
 EXPORT_SYMBOL(__release_sock);
 EXPORT_SYMBOL(net_timer);
 /* UDP/TCP exported functions for TCPv6 */
+EXPORT_SYMBOL(sysctl_tcp_sack);
+EXPORT_SYMBOL(sysctl_tcp_timestamps);
+EXPORT_SYMBOL(sysctl_tcp_window_scaling);
+EXPORT_SYMBOL(sock_rspace);
 EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_connect);
 EXPORT_SYMBOL(udp_sendmsg);
diff -u --recursive --new-file v2.1.36/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.36/linux/net/rose/af_rose.c	Mon Apr 14 16:28:28 1997
+++ linux/net/rose/af_rose.c	Mon May 12 10:35:45 1997
@@ -52,6 +52,7 @@
 #include <net/ip.h>
 #include <net/arp.h>
 #include <linux/if_arp.h>
+#include <linux/init.h>
 
 int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0;
 int sysctl_rose_call_request_timeout    = ROSE_DEFAULT_T1;
@@ -1381,7 +1382,7 @@
 	{"rose5", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}
 };
 
-void rose_proto_init(struct net_proto *pro)
+__initfunc(void rose_proto_init(struct net_proto *pro))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c
--- v2.1.36/linux/net/rose/sysctl_net_rose.c	Sun Feb  2 05:18:52 1997
+++ linux/net/rose/sysctl_net_rose.c	Mon May 12 10:35:45 1997
@@ -7,6 +7,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/init.h>
 #include <net/ax25.h>
 #include <net/rose.h>
 
@@ -58,7 +59,7 @@
 	{0}
 };
 
-void rose_register_sysctl(void)
+__initfunc(void rose_register_sysctl(void))
 {
 	rose_table_header = register_sysctl_table(rose_root_table, 1);
 }
diff -u --recursive --new-file v2.1.36/linux/net/socket.c linux/net/socket.c
--- v2.1.36/linux/net/socket.c	Fri Apr  4 08:52:29 1997
+++ linux/net/socket.c	Mon May 12 10:35:45 1997
@@ -71,6 +71,7 @@
 #include <linux/proc_fs.h>
 #include <linux/firewall.h>
 #include <linux/wanrouter.h>
+#include <linux/init.h>
 
 #if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
 #include <linux/kerneld.h>
@@ -207,7 +208,6 @@
 		file->f_op = &socket_file_ops;
 		file->f_mode = 3;
 		file->f_flags = O_RDWR;
-		file->f_count = 1;
 		file->f_inode = inode;
 		if (inode) 
 			inode->i_count++;
@@ -1400,7 +1400,7 @@
 	return 0;
 }
 
-void proto_init(void)
+__initfunc(void proto_init(void))
 {
 	extern struct net_proto protocols[];	/* Network protocols */
 	struct net_proto *pro;
@@ -1417,7 +1417,7 @@
 
 extern void sk_init(void);
 
-void sock_init(void)
+__initfunc(void sock_init(void))
 {
 	int i;
 
diff -u --recursive --new-file v2.1.36/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.36/linux/net/unix/af_unix.c	Wed Apr 23 19:01:30 1997
+++ linux/net/unix/af_unix.c	Mon May 12 10:35:45 1997
@@ -81,6 +81,7 @@
 #include <net/af_unix.h>
 #include <linux/proc_fs.h>
 #include <net/scm.h>
+#include <linux/init.h>
 
 #include <asm/checksum.h>
 
@@ -1459,7 +1460,7 @@
 	unix_create
 };
 
-void unix_proto_init(struct net_proto *pro)
+__initfunc(void unix_proto_init(struct net_proto *pro))
 {
 	struct sk_buff *dummy_skb;
 	struct proc_dir_entry *ent;
diff -u --recursive --new-file v2.1.36/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.1.36/linux/net/wanrouter/wanmain.c	Sun Feb  2 05:18:52 1997
+++ linux/net/wanrouter/wanmain.c	Mon May 12 10:35:45 1997
@@ -34,6 +34,7 @@
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/uaccess.h>	/* copy_to/from_user */
 #include <linux/wanrouter.h>	/* WAN router API definitions */
+#include <linux/init.h>		/* __initfunc et al. */
 
 /****** Defines and Macros **************************************************/
 
@@ -130,7 +131,7 @@
 
 #else
 
-void wanrouter_init(void)
+__initfunc(void wanrouter_init(void))
 {
 	int err = wanrouter_proc_init();
 	if (err) printk(KERN_ERR
diff -u --recursive --new-file v2.1.36/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.1.36/linux/net/wanrouter/wanproc.c	Mon Mar 17 14:54:36 1997
+++ linux/net/wanrouter/wanproc.c	Mon May 12 10:35:45 1997
@@ -23,6 +23,7 @@
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
+#include <linux/init.h>		/* __initfunc et al. */
 #include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/uaccess.h>	/* copy_to_user */
@@ -271,7 +272,7 @@
  *	Initialize router proc interface.
  */
 
-int wanrouter_proc_init (void)
+__initfunc(int wanrouter_proc_init (void))
 {
 	int err = proc_register(&proc_net, &proc_router);
 
diff -u --recursive --new-file v2.1.36/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.36/linux/net/x25/af_x25.c	Mon Apr 14 16:28:29 1997
+++ linux/net/x25/af_x25.c	Mon May 12 10:35:45 1997
@@ -45,6 +45,7 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/if_arp.h>
+#include <linux/init.h>
 #include <net/x25.h>
 
 int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
@@ -1283,7 +1284,7 @@
 };
 #endif	
 
-void x25_proto_init(struct net_proto *pro)
+__initfunc(void x25_proto_init(struct net_proto *pro))
 {
 	sock_register(&x25_family_ops);
 
diff -u --recursive --new-file v2.1.36/linux/net/x25/sysctl_net_x25.c linux/net/x25/sysctl_net_x25.c
--- v2.1.36/linux/net/x25/sysctl_net_x25.c	Wed Dec 18 02:07:56 1996
+++ linux/net/x25/sysctl_net_x25.c	Mon May 12 10:35:45 1997
@@ -10,6 +10,7 @@
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/netdevice.h>
+#include <linux/init.h>
 #include <net/x25.h>
 
 static int min_timer[] = {1   * X25_SLOWHZ};
@@ -46,7 +47,7 @@
 	{0}
 };
 
-void x25_register_sysctl(void)
+__initfunc(void x25_register_sysctl(void))
 {
 	x25_table_header = register_sysctl_table(x25_root_table, 1);
 }
diff -u --recursive --new-file v2.1.36/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.1.36/linux/scripts/mkdep.c	Fri Apr  4 08:52:29 1997
+++ linux/scripts/mkdep.c	Mon May 12 10:35:45 1997
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/fcntl.h>
 #include <sys/mman.h>
 
