diff -u --recursive --new-file lx2.0/v2.0.21/linux/CREDITS linux/CREDITS
--- lx2.0/v2.0.21/linux/CREDITS	Fri Sep 20 17:00:33 1996
+++ linux/CREDITS	Thu Sep 26 07:54:52 1996
@@ -1320,7 +1320,7 @@
 E: Linus.Torvalds@Helsinki.FI
 W: http://www.cs.helsinki.fi/~torvalds/
 P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A  BE 67 3C 24 03 13 62 C8
-D: General kernel hacker
+D: Original kernel hacker
 S: Kalevankatu 55 B 37
 S: 00180 Helsinki
 S: Finland
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/CodingStyle linux/Documentation/CodingStyle
--- lx2.0/v2.0.21/linux/Documentation/CodingStyle	Thu Jan  4 07:43:40 1996
+++ linux/Documentation/CodingStyle	Tue Sep 24 07:54:40 1996
@@ -183,14 +183,8 @@
   "C mode with adjusted defaults for use with the Linux kernel."
   (interactive)
   (c-mode)
-  (setq c-indent-level 8)
-  (setq c-brace-imaginary-offset 0)
-  (setq c-brace-offset -8)
-  (setq c-argdecl-indent 8)
-  (setq c-label-offset -8)
-  (setq c-continued-statement-offset 8)
-  (setq indent-tabs-mode nil)
-  (setq tab-width 8))
+  (c-set-style "K&R")
+  (setq c-basic-offset 8))
 
 This will define the M-x linux-c-mode command.  When hacking on a
 module, if you put the string -*- linux-c -*- somewhere on the first
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/IO-mapping.txt linux/Documentation/IO-mapping.txt
--- lx2.0/v2.0.21/linux/Documentation/IO-mapping.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/IO-mapping.txt	Sat Sep 28 11:05:38 1996
@@ -0,0 +1,202 @@
+
+[ This is a mail-message in response to a query on IO mapping, thus the
+  strange format for a "document" ]
+
+The aha1542 is a bus-master device, and your patch makes the driver give the
+controller the physical address of the buffers, which is correct on x86
+(because all bus master devices see the physical memory mappings directly). 
+
+However, on many setups, there are actually _three_ different ways of looking
+at memory addresses, and in this case we actually want the third, the
+so-called "bus address". 
+
+Essentially, the three ways of addressing memory are (this is "real memory",
+ie normal RAM, see later about other details): 
+
+ - CPU untranslated. This is the "physical" address, ie physical address 
+   0 is what the CPU sees when it drives zeroes on the memory bus.
+
+ - CPU translated address. This is the "virtual" address, and is 
+   completely internal to the CPU itself with the CPU doing the appropriate
+   translations into "CPU untranslated". 
+
+ - bus address. This is the address of memory as seen by OTHER devices, 
+   not the CPU. Now, in theory there could be many different bus 
+   addresses, with each device seeing memory in some device-specific way, but
+   happily most hardware designers aren't actually actively trying to make
+   things any more complex than necessary, so you can assume that all 
+   external hardware sees the memory the same way. 
+
+Now, on normal PC's the bus address is exactly the same as the physical
+address, and things are very simple indeed. However, they are that simple
+because the memory and the devices share the same address space, and that is
+not generally necessarily true on other PCI/ISA setups. 
+
+Now, just as an example, on the PReP (PowerPC Reference Platform), the 
+CPU sees a memory map something like this (this is from memory):
+
+	0-2GB	"real memory"
+	2GB-3GB	"system IO" (ie inb/out type accesses on x86)
+	3GB-4GB "IO memory" (ie shared memory over the IO bus)
+
+Now, that looks simple enough. However, when you look at the same thing from
+the viewpoint of the devices, you have the reverse, and the physical memory
+address 0 actually shows up as address 2GB for any IO master.
+
+So when the CPU wants any bus master to write to physical memory 0, it 
+has to give the master address 0x80000000 as the memory address.
+
+So, for example, depending on how the kernel is actually mapped on the 
+PPC, you can end up with a setup like this:
+
+ physical address:	0
+ virtual address:	0xC0000000
+ bus address:		0x80000000
+
+where all the addresses actually point to the same thing, it's just seen 
+through different translations..
+
+Similarly, on the alpha, the normal translation is
+
+ physical address:	0
+ virtual address:	0xfffffc0000000000
+ bus address:		0x40000000
+
+(but there are also alpha's where the physical address and the bus address
+are the same). 
+
+Anyway, the way to look up all these translations, you do
+
+	#include <asm/io.h>
+
+	phys_addr = virt_to_phys(virt_addr);
+	virt_addr = phys_to_virt(phys_addr);
+	 bus_addr = virt_to_bus(virt_addr);
+	virt_addr = bus_to_virt(bus_addr);
+
+Now, when do you need these?
+
+You want the _virtual_ address when you are actually going to access that 
+pointer from the kernel. So you can have something like this:
+
+	/*
+	 * this is the hardware "mailbox" we use to communicate with
+	 * the controller. The controller sees this directly.
+	 */
+	struct mailbox {
+		__u32 status;
+		__u32 bufstart;
+		__u32 buflen;
+		..
+	} mbox;
+
+		unsigned char * retbuffer;
+
+		/* get the address from the controller */
+		retbuffer = bus_to_virt(mbox.bufstart);
+		switch (retbuffer[0]) {
+			case STATUS_OK:
+				...
+
+on the other hand, you want the bus address when you have a buffer that 
+you want to give to the controller:
+
+	/* ask the controller to read the sense status into "sense_buffer" */
+	mbox.bufstart = virt_to_bus(&sense_buffer);
+	mbox.buflen = sizeof(sense_buffer);
+	mbox.status = 0;
+	notify_controller(&mbox);
+
+And you generally _never_ want to use the physical address, because you can't
+use that from the CPU (the CPU only uses translated virtual addresses), and
+you can't use it from the bus master. 
+
+So why do we care about the physical address at all? We do need the physical
+address in some cases, it's just not very often in normal code.  The physical
+address is needed if you use memory mappings, for example, because the
+"remap_page_range()" mm function wants the physical address of the memory to
+be remapped (the memory management layer doesn't know about devices outside
+the CPU, so it shouldn't need to know about "bus addresses" etc). 
+
+NOTE NOTE NOTE! The above is only one part of the whole equation. The above
+only talks about "real memory", ie CPU memory, ie RAM. 
+
+There is a completely different type of memory too, and that's the "shared
+memory" on the PCI or ISA bus. That's generally not RAM (although in the case
+of a video graphics card it can be normal DRAM that is just used for a frame
+buffer), but can be things like a packet buffer in a network card etc. 
+
+This memory is called "PCI memory" or "shared memory" or "IO memory" or
+whatever, and there is only one way to access it: the readb/writeb and
+related functions. You should never take the address of such memory, because
+there is really nothing you can do with such an address: it's not
+conceptually in the same memory space as "real memory" at all, so you cannot
+just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
+so on x86 it actually works to just deference a pointer, but it's not
+portable). 
+
+For such memory, you can do things like
+
+ - reading:
+	/*
+	 * read first 32 bits from ISA memory at 0xC0000, aka
+	 * C000:0000 in DOS terms
+	 */
+	unsigned int signature = readl(0xC0000);
+
+ - remapping and writing:
+	/*
+	 * remap framebuffer PCI memory area at 0xFC000000,
+	 * size 1MB, so that we can access it: We can directly
+	 * access only the 640k-1MB area, so anything else
+	 * has to be remapped.
+	 */
+	char * baseptr = ioremap(0xFC000000, 1024*1024);
+
+	/* write a 'A' to the offset 10 of the area */
+	writeb('A',baseptr+10);
+
+	/* unmap when we unload the driver */
+	iounmap(baseptr);
+
+ - copying and clearing:
+	/* get the 6-byte ethernet address at ISA address E000:0040 */
+	memcpy_fromio(kernel_buffer, 0xE0040, 6);
+	/* write a packet to the driver */
+	memcpy_toio(0xE1000, skb->data, skb->len);
+	/* clear the frame buffer */
+	memset_io(0xA0000, 0, 0x10000);
+
+Ok, that just about covers the basics of accessing IO portably.  Questions?
+Comments? You may think that all the above is overly complex, but one day you
+might find yourself with a 500MHz alpha in front of you, and then you'll be
+happy that your driver works ;)
+
+Note that kernel versions 2.0.x (and earlier) mistakenly called the
+ioremap() function "vremap()".  ioremap() is the proper name, but I
+didn't think straight when I wrote it originally.  People who have to
+support both can do something like:
+ 
+	/* support old naming sillyness */
+	#if LINUX_VERSION_CODE < 0x020100                                     
+	#define ioremap vremap
+	#define iounmap vfree                                                     
+	#endif
+ 
+at the top of their source files, and then they can use the right names
+even on 2.0.x systems. 
+
+And the above sounds worse than it really is.  Most real drivers really
+don't do all that complex things (or rather: the complexity is not so
+much in the actual IO accesses as in error handling and timeouts etc). 
+It's generally not hard to fix drivers, and in many cases the code
+actually looks better afterwards:
+
+	unsigned long signature = *(unsigned int *) 0xC0000;
+		vs
+	unsigned long signature = readl(0xC0000);
+
+I think the second version actually is more readable, no?
+
+		Linus
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- lx2.0/v2.0.21/linux/Documentation/cdrom/ide-cd	Fri Sep 20 17:00:33 1996
+++ linux/Documentation/cdrom/ide-cd	Wed Sep 25 11:11:47 1996
@@ -352,6 +352,14 @@
     bug.
 
 
+f. Data corruption.
+
+  - Random data corruption was occasionally observed with the Hitachi
+    CDR-7730 cdrom. If you experience data corruption, using "hdx=slow"
+    as a command line parameter may work around the problem, at the
+    expense of low system performance.
+
+
 6. cdload.c
 -----------
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/ide.txt linux/Documentation/ide.txt
--- lx2.0/v2.0.21/linux/Documentation/ide.txt	Sat Aug 10 10:03:14 1996
+++ linux/Documentation/ide.txt	Wed Sep 25 11:11:47 1996
@@ -255,6 +255,8 @@
 				Not fully supported by all chipset types,
 				and quite likely to cause trouble with
 				older/odd IDE drives.
+ "hdx=slow"		: insert a huge pause after each access to the data
+				port. Should be used only as a last resort.
 
  "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in Mhz,
 				where "xx" is between 20 and 66 inclusive,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/locks.txt linux/Documentation/locks.txt
--- lx2.0/v2.0.21/linux/Documentation/locks.txt	Wed May 15 11:22:04 1996
+++ linux/Documentation/locks.txt	Sun Sep 22 09:41:32 1996
@@ -2,14 +2,14 @@
 
 		Andy Walker <andy@lysaker.kvaerner.no>
 
-			    15 May 1996
+			    21 Sep 1996
 
 
-What's New?
------------
+1. What's New?
+--------------
 
-Flock Emulation Warnings
-------------------------
+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:
@@ -23,16 +23,21 @@
 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 are 5.2.18 or 5.3.12 for ELF, and I believe
-somebody made a 4.7.6 release for people using a.out systems.
+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.
+
 
-In 1.3.96 Linus decided to be lenient on the stragglers and changed the
-warning message so that the kernel will only complain five times and
-then shut up. That should make life more bearable even for people who,
-for some reason, don't want to upgrade.
+1.2 Disallow Mixed Locks
+------------------------
 
-Sendmail Problems
------------------
+1.2.1 Sendmail Problems
+---------------------
 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
@@ -42,8 +47,9 @@
 over time, or under a very heavy mail load, would eventually cause the kernel
 to lock solid with deadlocked processes.
 
-Disallow Mixed Locks
---------------------
+
+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.
@@ -61,4 +67,3 @@
 sendmail may have problems running in 'newaliases' mode. It will no longer
 deadlock though. Recompile sendmail to use flock() and your troubles will
 be over.
-
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Documentation/mandatory.txt linux/Documentation/mandatory.txt
--- lx2.0/v2.0.21/linux/Documentation/mandatory.txt	Tue Apr 16 10:27:10 1996
+++ linux/Documentation/mandatory.txt	Sun Sep 22 09:41:32 1996
@@ -5,8 +5,8 @@
 			   15 April 1996
 
 
-What is  mandatory locking?
----------------------------
+1. What is  mandatory locking?
+------------------------------
 
 Mandatory locking is kernel enforced file locking, as opposed to the more usual
 cooperative file locking used to guarantee sequential access to files among
@@ -44,8 +44,8 @@
 borrowing the fcntl() locking scheme from System V. The mandatory locking
 scheme is defined by the System V Interface Definition (SVID) Version 3.
 
-Marking a file for mandatory locking
-------------------------------------
+2. Marking a file for mandatory locking
+---------------------------------------
 
 A file is marked as a candidate for mandatory by setting the group-id bit in
 its file mode but removing the group-execute bit. This is an otherwise
@@ -58,8 +58,8 @@
 refrain from clearing this bit. Similarly the kernel has been modified not
 to run mandatory lock candidates with setgid privileges.
 
-Available implementations
--------------------------
+3. Available implementations
+----------------------------
 
 I have considered the implementations of mandatory locking available with
 SunOS 4.1.x, Solaris 2.x and HP-UX 9.x.
@@ -93,8 +93,8 @@
 below are just as valid as any others, so long as the main points seem to
 agree. 
 
-Semantics
----------
+4. Semantics
+------------
 
 1. Mandatory locks can only be applied via the fcntl()/lockf() locking
    interface - in other words the System V/POSIX interface. BSD style
@@ -124,8 +124,8 @@
    that has any mandatory locks in effect will be rejected with the error status
    EAGAIN.
 
-Which system calls are affected?
---------------------------------
+5. Which system calls are affected?
+-----------------------------------
 
 Those which modify a file's contents, not just the inode. That gives read(),
 write(), readv(), writev(), open(), creat(), mmap(), truncate() and
@@ -142,8 +142,8 @@
 checking in my eagerness to get this code out the door. Please let me know, or
 better still fix the system calls yourself and submit a patch to me or Linus.
 
-Warning!
---------
+6. Warning!
+-----------
 
 Not even root can override a mandatory lock, so runaway process can wreak
 havoc if they lock crucial files. The way around it is to change the file
diff -u --recursive --new-file lx2.0/v2.0.21/linux/MAINTAINERS linux/MAINTAINERS
--- lx2.0/v2.0.21/linux/MAINTAINERS	Sun Sep 15 10:34:18 1996
+++ linux/MAINTAINERS	Sun Sep 22 09:41:32 1996
@@ -159,6 +159,12 @@
 L:	linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu
 S:	Maintained
 
+FILE LOCKING (flock() and fcntl()/lockf())
+P:	Andy Walker
+M:	andy@lysaker.kvaerner.no
+L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
 P:	Mike McLagan
 M:	mike.mclagan@linux.org
diff -u --recursive --new-file lx2.0/v2.0.21/linux/Makefile linux/Makefile
--- lx2.0/v2.0.21/linux/Makefile	Fri Sep 20 17:00:33 1996
+++ linux/Makefile	Mon Sep 23 17:53:37 1996
@@ -1,6 +1,6 @@
 VERSION = 2
-PATCHLEVEL = 0
-SUBLEVEL = 21
+PATCHLEVEL = 1
+SUBLEVEL = 0
 
 ARCH = i386
 
@@ -26,7 +26,7 @@
 HPATH   	= $(TOPDIR)/include
 FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
 
-HOSTCC  	=gcc -I$(HPATH)
+HOSTCC  	=gcc
 HOSTCFLAGS	=-O2 -fomit-frame-pointer
 
 CROSS_COMPILE 	=
diff -u --recursive --new-file lx2.0/v2.0.21/linux/README linux/README
--- lx2.0/v2.0.21/linux/README	Wed Jun 26 11:05:26 1996
+++ linux/README	Tue Sep 24 07:54:40 1996
@@ -1,10 +1,24 @@
 
-	Linux kernel release 2.0.xx
+	Linux kernel release 2.1.xx
 
-These are the release notes for linux version 2.0.  Read them carefully,
+These are the release notes for linux version 2.1.  Read them carefully,
 as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong. 
 
+Linux version 2.1 is a DEVELOPMENT kernel, and not intended for general
+public use.  Different releases may have various and sometimes severe
+bugs.  It is *strongly* recommended that you back up the previous kernel
+before installing any new 2.1.xx release.
+
+If you need to use a proven and stable Linux kernel, please use 1.0.9,
+1.2.13, or 2.0.xx.  All features which will be in the 2.1.xx releases will
+be contained in 2.2.xx when the code base has stabilized again.
+
+If you decide to use 2.1, it is recommended that you join the kernel mailing
+list.  To do this, e-mail majordomo@vger.rutgers.edu, and put in the body
+of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest"
+for a daily digest of the mailing list (it is a high-traffic list.)
+
 WHAT IS LINUX?
 
   Linux is a Unix clone written from scratch by Linus Torvalds with
@@ -27,7 +41,7 @@
 
 DOCUMENTATION:
 
- - there is a lot of documentation available both in electronic form on
+ - There is a lot of documentation available both in electronic form on
    the internet and in books, both Linux-specific and pertaining to
    general UNIX questions.  I'd recommend looking into the documentation
    subdirectories on any Linux ftp site for the LDP (Linux Documentation
@@ -44,13 +58,13 @@
  - If you install the full sources, do a
 
 		cd /usr/src
-		gzip -cd linux-2.0.XX.tar.gz | tar xfv -
+		gzip -cd linux-2.1.XX.tar.gz | tar xfv -
 
    to get it all put in place. Replace "XX" with the version number of the
    latest kernel.
 
- - You can also upgrade between 2.0.xx releases by patching.  Each
-   patch that is released for 2.0.xx contains only bugfixes.  No
+ - You can also upgrade between 2.1.xx releases by patching.  Each
+   patch that is released for 2.1.xx contains only bugfixes.  No
    new features will be added to the Linux kernel until the 2.1.xx
    development effort begins.  To install by patching, get all the
    newer patch files and do
@@ -76,7 +90,7 @@
    the current directory, but an alternative directory can be specified
    as the second argument.
 
- - make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi
+ - Make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi
    directories are just symlinks to the kernel sources:
 
 		cd /usr/include
@@ -85,7 +99,7 @@
 		ln -s /usr/src/linux/include/linux linux
 		ln -s /usr/src/linux/include/scsi scsi
 
- - make sure you have no stale .o files and dependencies lying around:
+ - Make sure you have no stale .o files and dependencies lying around:
 
 		cd /usr/src/linux
 		make mrproper
@@ -94,7 +108,7 @@
 
 CONFIGURING the kernel:
 
- - do a "make config" to configure the basic kernel.  "make config"
+ - Do a "make config" to configure the basic kernel.  "make config"
    needs bash to work: it will search for bash in $BASH, /bin/bash and
    /bin/sh (in that order), so hopefully one of those is correct. 
 
@@ -128,26 +142,28 @@
 
 COMPILING the kernel:
 
- - make sure you have gcc-2.6.3 or newer available.  It seems older gcc
-   versions can have problems compiling newer versions of linux.  If you
-   upgrade your compiler, remember to get the new binutils package too
+ - Make sure you have gcc-2.7.0 or newer available.  It seems older gcc
+   versions can have problems compiling newer versions of linux.  This
+   is mainly because they only compile programs in the a.out binary
+   format.  As of Linux 2.1.0, the kernel must be compiled as ELF.  If
+   you upgrade your compiler, remember to get the new binutils package too
    (for as/ld/nm and company).
 
- - do a "make zImage" to create a compressed kernel image.  If you want
+ - Do a "make zImage" to create a compressed kernel image.  If you want
    to make a bootdisk (without root filesystem or lilo), insert a floppy
    in your A: drive, and do a "make zdisk".  It is also possible to do
    "make zlilo" if you have lilo installed to suit the kernel makefiles,
    but you may want to check your particular lilo setup first. 
 
- - if your kernel is too large for "make zImage", use "make bzImage"
+ - If your kernel is too large for "make zImage", use "make bzImage"
    instead.
 
- - if you configured any of the parts of the kernel as `modules', you
+ - If you configured any of the parts of the kernel as `modules', you
    will have to do "make modules" followed by "make modules_install".
    Read Documentation/modules.txt for more information.  For example,
    an explanation of how to use the modules is included there.
 
- - keep a backup kernel handy in case something goes wrong.  This is 
+ - Keep a backup kernel handy in case something goes wrong.  This is 
    especially true for the development releases, since each new release
    contains new code which has not been debugged. 
 
@@ -157,9 +173,9 @@
 
    For some, this is on a floppy disk, in which case you can "cp
    /usr/src/linux/arch/i386/boot/zImage /dev/fd0" to make a bootable
-   floppy.  Note that as of Linux 2.0.0, a kernel copied to a 720k
-   double-density 3.5" floppy disk no longer boots.  In this case,
-   it is highly recommended that you install LILO on your
+   floppy.  Note that a change in the 1.3.x series prevented a kernel
+   copied to a 720k double-density 3.5" floppy from booting.  In this
+   case, it is highly recommended that you install LILO on your
    double-density bootfloppy or switch to high-density floppies.
 
    If you boot Linux from the hard drive, chances are you use LILO which
@@ -183,11 +199,11 @@
    alternatively the LILO boot options when appropriate).  No need to
    recompile the kernel to change these parameters. 
 
- - reboot with the new kernel and enjoy. 
+ - Reboot with the new kernel and enjoy. 
 
 IF SOMETHING GOES WRONG:
 
- - if you have problems that seem to be due to kernel bugs, please check
+ - If you have problems that seem to be due to kernel bugs, please check
    the file MAINTAINERS to see if there is a particular person associated
    with the part of the kernel that you are having trouble with. If there
    isn't anyone listed there, then the second best thing is to mail
@@ -201,7 +217,7 @@
    sense).  If the problem is new, tell me so, and if the problem is
    old, please try to tell me when you first noticed it.
 
- - if the bug results in a message like
+ - If the bug results in a message like
 
 	unable to handle kernel paging request at address C0000010
 	Oops: 0002
@@ -224,7 +240,7 @@
    the C++ sources under the scripts/ directory to avoid having to do
    the dump lookup by hand:
 
- - in debugging dumps like the above, it helps enormously if you can
+ - In debugging dumps like the above, it helps enormously if you can
    look up what the EIP value means.  The hex value as such doesn't help
    me or anybody else very much: it will depend on your particular
    kernel setup.  What you should do is take the hex value from the EIP
@@ -255,7 +271,7 @@
    kernel image or similar), telling me as much about your setup as
    possible will help. 
 
- - alternately, you can use gdb on a running kernel. (read-only; i.e. you
+ - Alternately, you can use gdb on a running kernel. (read-only; i.e. you
    cannot change values or set break points.) To do this, first compile the
    kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
    clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- lx2.0/v2.0.21/linux/arch/alpha/kernel/ptrace.c	Wed Sep 11 17:57:13 1996
+++ linux/arch/alpha/kernel/ptrace.c	Mon Sep 23 14:41:33 1996
@@ -197,7 +197,7 @@
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page >= high_memory)
+	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 	page += addr & ~PAGE_MASK;
 	return *(unsigned long *) page;
@@ -252,7 +252,7 @@
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page < high_memory)
+	if (MAP_NR(page) < max_mapnr)
 		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- lx2.0/v2.0.21/linux/arch/alpha/mm/init.c	Wed Aug 21 09:18:07 1996
+++ linux/arch/alpha/mm/init.c	Wed Sep 25 12:14:59 1996
@@ -59,7 +59,7 @@
 	printk("\nMem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	i = MAP_NR(high_memory);
+	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
 		if (PageReserved(mem_map+i))
@@ -145,7 +145,8 @@
 	unsigned long tmp;
 
 	end_mem &= PAGE_MASK;
-	high_memory = end_mem;
+	max_mapnr = MAP_NR(end_mem);
+	high_memory = (void *) end_mem;
 	start_mem = PAGE_ALIGN(start_mem);
 
 	/*
@@ -157,7 +158,7 @@
 		tmp += PAGE_SIZE;
 	}
 
-	for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) {
+	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp)))
@@ -174,7 +175,7 @@
 {
 	int i;
 
-	i = MAP_NR(high_memory);
+	i = max_mapnr;
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- lx2.0/v2.0.21/linux/arch/i386/Makefile	Thu Jul 25 19:35:00 1996
+++ linux/arch/i386/Makefile	Thu Sep 26 07:39:10 1996
@@ -13,27 +13,25 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
+AS86    =$(CROSS_COMPILE)as86 -0 -a
+AS386   =$(CROSS_COMPILE)as86 -3
+LD86    =$(CROSS_COMPILE)ld86 -0
+
 #
-# Set these to indicate how to link it..
-#
-# -zmagic:   (aout, old GCC-2.5.2)
-#
-# ZLINKFLAGS   = -Ttext 0x1000
-# BZLINKFLAGS  = -Ttext 0x100000     # (for big high loaded kernels)
-# LINKFLAGS    = -Ttext 0x100000
+# ZIMAGE_OFFSET is the load offset of the compression loader
+# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
 #
-# -qmagic:   (aout)
+ZIMAGE_OFFSET=0x1000
+BZIMAGE_OFFSET=0x100000
+
 #
-# ZLINKFLAGS   = -Ttext 0x0xfe0
-# BZLINKFLAGS  = -Ttext 0xfffe0      # (for big high loaded kernels)
-# LINKFLAGS    = -Ttext 0xfffe0
+# IMAGE_OFFSET is the load offset of the _real_ kernel, soon
+# to be offset by another 0xC0000000...
 #
+IMAGE_OFFSET=0xC0100000
 
-AS86    =$(CROSS_COMPILE)as86 -0 -a
-AS386   =$(CROSS_COMPILE)as86 -3
-LD86    =$(CROSS_COMPILE)ld86 -0
-
-ifdef CONFIG_KERNEL_ELF
+# This is used for ELF - it needs to migrate or be moved.
+LD_RFLAG = -m elf_i386
 
 LD=$(CROSS_COMPILE)ld -m elf_i386
 CPP=$(CC) -E -D__ELF__
@@ -43,21 +41,9 @@
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr
 ZLDFLAGS=-e startup_32 
 LDFLAGS=-e stext
-ZIMAGE_OFFSET=0x1000
-IMAGE_OFFSET=0x100000
 ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
-BZLINKFLAGS =-Ttext $(IMAGE_OFFSET) $(ZLDFLAGS)
+BZLINKFLAGS =-Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
 LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS)
-
-else
-
-#
-# -qmagic (we need to remove the 32 byte header for bootup purposes)
-#
-ZLINKFLAGS =-qmagic -Ttext 0xfe0
-BZLINKFLAGS =-qmagic -Ttext 0xfffe0
-LINKFLAGS =-qmagic -Ttext 0xfffe0
-endif
 
 CFLAGS := $(CFLAGS) -pipe
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- lx2.0/v2.0.21/linux/arch/i386/boot/Makefile	Wed Jul 17 14:59:14 1996
+++ linux/arch/i386/boot/Makefile	Fri Sep 20 18:43:03 1996
@@ -8,38 +8,28 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-ifdef CONFIG_KERNEL_ELF
 HOSTCFLAGS := $(HOSTCFLAGS) -D__BFD__
-endif
 
 ifdef SMP
 HOSTCFLAGS := $(HOSTCFLAGS) -D__SMP__
 endif
 
 zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
-ifdef CONFIG_KERNEL_ELF
 	if hash $(ENCAPS) 2> /dev/null; then \
 	  $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out; \
 	else \
 	  $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out; \
 	fi
 	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
-else
-	tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage
-endif
 	sync
 
 bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild
-ifdef CONFIG_KERNEL_ELF
 	if hash $(ENCAPS) 2> /dev/null; then \
 	  $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \
 	else \
 	  $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \
 	fi
 	tools/bbuild bbootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
-else
-	tools/bbuild bbootsect setup compressed/bvmlinux $(ROOT_DEV) > bzImage
-endif
 	sync
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- lx2.0/v2.0.21/linux/arch/i386/boot/compressed/Makefile	Sun Sep  8 19:50:20 1996
+++ linux/arch/i386/boot/compressed/Makefile	Fri Sep 20 18:46:05 1996
@@ -15,11 +15,9 @@
 CFLAGS := $(CFLAGS) -D__SMP__
 endif
 
-ifdef CONFIG_KERNEL_ELF
 TARGET=--target elf32-i386
 INPUT_DATA=input_data
 INPUT_LEN=input_len
-endif
 
 all: vmlinux
 
@@ -41,7 +39,6 @@
 
 endif
 
-ifdef CONFIG_KERNEL_ELF
 
 # You cannot compress a file and have the kernel uncompress it, it must
 # be stdin
@@ -61,18 +58,6 @@
 	  $(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
 	fi; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
-else
-
-piggy.o:	$(SYSTEM) xtract piggyback
-		./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o
-
-xtract: xtract.c
-	$(HOSTCC) $(CFLAGS) -o xtract xtract.c
-
-piggyback: piggyback.c
-	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
-endif
 
 clean:
 	rm -f xtract piggyback vmlinux bvmlinux
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c
--- lx2.0/v2.0.21/linux/arch/i386/boot/compressed/misc.c	Mon Jul 15 13:47:39 1996
+++ linux/arch/i386/boot/compressed/misc.c	Mon Sep 23 11:29:03 1996
@@ -21,6 +21,8 @@
 #define OF(args)  args
 #define STATIC static
 
+#undef memset
+#undef memcpy
 #define memzero(s, n)     memset ((s), 0, (n))
 
 typedef unsigned char  uch;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/config.in linux/arch/i386/config.in
--- lx2.0/v2.0.21/linux/arch/i386/config.in	Mon May 13 07:17:23 1996
+++ linux/arch/i386/config.in	Fri Sep 20 18:40:25 1996
@@ -36,7 +36,6 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
-bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
 
 choice 'Processor type' \
 	"386		CONFIG_M386	\
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- lx2.0/v2.0.21/linux/arch/i386/defconfig	Mon Aug  5 10:13:50 1996
+++ linux/arch/i386/defconfig	Fri Sep 20 18:43:49 1996
@@ -24,7 +24,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
 CONFIG_M586=y
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/bios32.c	Sat Jun  8 11:10:49 1996
+++ linux/arch/i386/kernel/bios32.c	Mon Sep 23 13:22:07 1996
@@ -55,6 +55,7 @@
 #include <linux/bios32.h>
 #include <linux/pci.h>
 
+#include <asm/page.h>
 #include <asm/segment.h>
 
 #define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
@@ -164,7 +165,7 @@
 	int pack;
 
 	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-		pci_indirect.address = pcibios_entry;
+		pci_indirect.address = pcibios_entry | PAGE_OFFSET;
 
 		__asm__("lcall (%%edi)\n\t"
 			"jc 1f\n\t"
@@ -417,7 +418,9 @@
 	 *
 	 */
 
-	for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
+	for (check = (union bios32 *) __va(0xe0000);
+	     check <= (union bios32 *) __va(0xffff0);
+	     ++check) {
 		if (check->fields.signature != BIOS32_SIGNATURE)
 			continue;
 		length = check->fields.length * 16;
@@ -438,8 +441,9 @@
 			if (check->fields.entry >= 0x100000) {
 				printk("pcibios_init: entry in high memory, unable to access\n");
 			} else {
-				bios32_indirect.address = bios32_entry = check->fields.entry;
+				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;
 			}
 		}
 	}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- lx2.0/v2.0.21/linux/arch/i386/kernel/entry.S	Wed Jul 17 12:33:25 1996
+++ linux/arch/i386/kernel/entry.S	Tue Sep 24 14:03:16 1996
@@ -38,6 +38,8 @@
  *	38(%esp) - %eflags
  *	3C(%esp) - %oldesp
  *	40(%esp) - %oldss
+ *
+ * "current" is in register %ebx during any slow entries.
  */
 
 #include <linux/sys.h>
@@ -99,9 +101,7 @@
 	pushl %ebx; \
 	movl $(KERNEL_DS),%edx; \
 	mov %dx,%ds; \
-	mov %dx,%es; \
-	movl $(USER_DS),%edx; \
-	mov %dx,%fs;
+	mov %dx,%es;
 
 #ifdef	__SMP__
 
@@ -194,13 +194,7 @@
 
 
 #define RESTORE_ALL \
-	cmpw $(KERNEL_CS),CS(%esp); \
-	je 1f;   \
-	GET_PROCESSOR_OFFSET(%edx) \
-	movl SYMBOL_NAME(current_set)(,%edx), %eax ; ; \
-	movl dbgreg7(%eax),%ebx; \
-	movl %ebx,%db7;	\
-1:	LEAVE_KERNEL \
+	LEAVE_KERNEL \
 	popl %ebx; \
 	popl %ecx; \
 	popl %edx; \
@@ -215,15 +209,16 @@
 	addl $4,%esp; \
 	iret
 
+#define GET_CURRENT \
+	GET_PROCESSOR_OFFSET(%ebx) \
+	movl SYMBOL_NAME(current_set)(%ebx),%ebx
+
 #else
 
+#define GET_CURRENT \
+	movl SYMBOL_NAME(current_set),%ebx
+
 #define RESTORE_ALL \
-	cmpw $(KERNEL_CS),CS(%esp); \
-	je 1f;   \
-	movl SYMBOL_NAME(current_set),%eax; \
-	movl dbgreg7(%eax),%ebx; \
-	movl %ebx,%db7;	\
-1:	\
 	popl %ebx; \
 	popl %ecx; \
 	popl %edx; \
@@ -244,6 +239,7 @@
 	pushfl			# We get a different stack layout with call gates,
 	pushl %eax		# which has to be cleaned up later..
 	SAVE_ALL
+	GET_CURRENT
 #ifdef __SMP__
 	ENTER_KERNEL
 #endif
@@ -281,6 +277,7 @@
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
+	GET_CURRENT
 #ifdef __SMP__
 	ENTER_KERNEL
 #endif
@@ -290,33 +287,11 @@
 	movl SYMBOL_NAME(sys_call_table)(,%eax,4),%eax
 	testl %eax,%eax
 	je ret_from_sys_call
-#ifdef __SMP__
-	GET_PROCESSOR_OFFSET(%edx)
-	movl SYMBOL_NAME(current_set)(,%edx),%ebx
-#else
-	movl SYMBOL_NAME(current_set),%ebx
-#endif
 	andl $~CF_MASK,EFLAGS(%esp)	# clear carry - assume no errors
-	movl %db6,%edx
-	movl %edx,dbgreg6(%ebx)  # save current hardware debugging status
 	testb $0x20,flags(%ebx)		# PF_TRACESYS
-	jne 1f
+	jne tracesys
 	call *%eax
 	movl %eax,EAX(%esp)		# save the return value
-	jmp ret_from_sys_call
-	ALIGN
-1:	call SYMBOL_NAME(syscall_trace)
-	movl ORIG_EAX(%esp),%eax
-	call SYMBOL_NAME(sys_call_table)(,%eax,4)
-	movl %eax,EAX(%esp)		# save the return value
-#ifdef __SMP__
-	GET_PROCESSOR_OFFSET(%eax)
-	movl SYMBOL_NAME(current_set)(,%eax),%eax
-#else
-	movl SYMBOL_NAME(current_set),%eax
-#endif
-	call SYMBOL_NAME(syscall_trace)
-
 	ALIGN
 	.globl ret_from_sys_call
 ret_from_sys_call:
@@ -336,18 +311,12 @@
 	movl %eax,EFLAGS(%esp)		# stupid
 	cmpl $0,SYMBOL_NAME(need_resched)
 	jne reschedule
-#ifdef __SMP__
-	GET_PROCESSOR_OFFSET(%eax)
-	movl SYMBOL_NAME(current_set)(,%eax), %eax
-#else
-	movl SYMBOL_NAME(current_set),%eax
-#endif
-	cmpl SYMBOL_NAME(task),%eax	# task[0] cannot have signals
+	cmpl SYMBOL_NAME(task),%ebx	# task[0] cannot have signals
 	je 2f
-	movl blocked(%eax),%ecx
-	movl %ecx,%ebx			# save blocked in %ebx for signal handling
+	movl blocked(%ebx),%ecx
+	movl %ecx,%eax			# save blocked in %eax for signal handling
 	notl %ecx
-	andl signal(%eax),%ecx
+	andl signal(%ebx),%ecx
 	jne signal_return
 2:	RESTORE_ALL
 	ALIGN
@@ -356,21 +325,32 @@
 	pushl %ecx
 	testl $(VM_MASK),EFLAGS(%ecx)
 	jne v86_signal_return
-	pushl %ebx
+	pushl %eax
 	call SYMBOL_NAME(do_signal)
-	popl %ebx
-	popl %ebx
+	popl %eax
+	popl %eax
 	RESTORE_ALL
 	ALIGN
 v86_signal_return:
+	pushl %eax
 	call SYMBOL_NAME(save_v86_state)
+	popl %edx
 	movl %eax,%esp
 	pushl %eax
-	pushl %ebx
+	pushl %edx
 	call SYMBOL_NAME(do_signal)
-	popl %ebx
-	popl %ebx
+	popl %edx
+	popl %edx
 	RESTORE_ALL
+	ALIGN
+tracesys:
+	call SYMBOL_NAME(syscall_trace)
+	movl ORIG_EAX(%esp),%eax
+	call SYMBOL_NAME(sys_call_table)(,%eax,4)
+	movl %eax,EAX(%esp)		# save the return value
+	call SYMBOL_NAME(syscall_trace)
+	jmp ret_from_sys_call
+
 
 ENTRY(divide_error)
 	pushl $0		# no error code
@@ -390,28 +370,21 @@
 	pushl %ecx
 	pushl %ebx
 	cld
-	xorl %ebx,%ebx			# zero ebx
+	xorl %ecx,%ecx			# zero ecx
 	xchgl %eax, ORIG_EAX(%esp)	# orig_eax (get the error code. )
 	mov %gs,%bx			# get the lower order bits of gs
 	movl %esp,%edx
-	xchgl %ebx, GS(%esp)		# get the address and save gs.
+	xchgl %ecx, GS(%esp)		# get the address and save gs.
 	pushl %eax			# push the error code
 	pushl %edx
 	movl $(KERNEL_DS),%edx
 	mov %dx,%ds
 	mov %dx,%es
-	movl $(USER_DS),%edx
-	mov %dx,%fs
+	GET_CURRENT
 #ifdef __SMP__
 	ENTER_KERNEL
-	GET_PROCESSOR_OFFSET(%eax)
-	movl SYMBOL_NAME(current_set)(,%eax), %eax
-#else
-	movl SYMBOL_NAME(current_set),%eax
 #endif
-	movl %db6,%edx
-	movl %edx,dbgreg6(%eax)  # save current hardware debugging status
-	call *%ebx
+	call *%ecx
 	addl $8,%esp
 	jmp ret_from_sys_call
 
@@ -423,6 +396,7 @@
 ENTRY(device_not_available)
 	pushl $-1		# mark this as an int
 	SAVE_ALL
+	GET_CURRENT
 #ifdef __SMP__
 	ENTER_KERNEL
 #endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- lx2.0/v2.0.21/linux/arch/i386/kernel/head.S	Mon Mar 18 13:15:00 1996
+++ linux/arch/i386/kernel/head.S	Mon Sep 23 09:33:40 1996
@@ -20,18 +20,34 @@
 #define CL_OFFSET	0x90022
 
 /*
- * swapper_pg_dir is the main page directory, address 0x00001000 (or at
- * address 0x00101000 for a compressed boot).
+ * swapper_pg_dir is the main page directory, address 0x00101000
  */
 ENTRY(stext)
 ENTRY(_stext)
 startup_32:
+/*
+ * Set segments to known values
+ */
 	cld
 	movl $(KERNEL_DS),%eax
 	mov %ax,%ds
 	mov %ax,%es
 	mov %ax,%fs
 	mov %ax,%gs
+/*
+ * Setup paging (the tables are already set up, just switch them on)
+ */
+	movl $0x101000,%eax
+	movl %eax,%cr3		/* set the page table pointer.. */
+	movl %cr0,%eax
+	orl $0x80000000,%eax
+	movl %eax,%cr0		/* ..and set paging (PG) bit */
+	jmp 1f			/* flush the prefetch-queue */
+1:
+	movl $1f,%eax
+	jmp *%eax		/* make sure eip is relocated */
+1:
+
 #ifdef __SMP__
 	orw  %bx,%bx
 	jz  1f				/* Initial CPU cleans BSS */
@@ -174,8 +190,6 @@
 	movb ready,%eax
 	orb %eax,%eax
 	jz 3f	
-	movl $ SYMBOL_NAME(swapper_pg_dir), %eax
-	movl %eax, %cr3
 #ifdef GAS_KNOWS_CR4
 	movl %cr4,%eax
 	orl $16,%eax
@@ -185,13 +199,9 @@
 	orl $16,%eax
 	.byte 0x0f,0x22,0xe0
 #endif
-	movl %cr0, %eax
-	orl $0x80000000, %eax
-	movl %eax, %cr0
 	jmp 4f
 #endif
 3:
-	call setup_paging
 #ifdef __SMP__
 	incb ready
 #endif
@@ -272,60 +282,159 @@
 
 
 /*
- * Setup_paging
- *
- * This routine sets up paging by setting the page bit
- * in cr0. The page tables are set up, identity-mapping
- * the first 4MB.  The rest are initialized later.
- *
- * (ref: added support for up to 32mb, 17Apr92)  -- Rik Faith
- * (ref: update, 25Sept92)  -- croutons@crunchy.uucp 
- * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
- */
-	ALIGN
-setup_paging:
-	movl $1024*2,%ecx		/* 2 pages - swapper_pg_dir+1 page table */
-	xorl %eax,%eax
-	movl $ SYMBOL_NAME(swapper_pg_dir),%edi	/* swapper_pg_dir is at 0x1000 */
-	cld;rep;stosl
-/* Identity-map the kernel in low 4MB memory for ease of transition */
-/* set present bit/user r/w */
-	movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
-/* But the real place is at 0xC0000000 */
-/* set present bit/user r/w */
-	movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
-	movl $ SYMBOL_NAME(pg0)+4092,%edi
-	movl $0x03ff007,%eax		/*  4Mb - 4096 + 7 (r/w user,p) */
-	std
-1:	stosl			/* fill the page backwards - more efficient :-) */
-	subl $0x1000,%eax
-	jge 1b
-	cld
-	movl $ SYMBOL_NAME(swapper_pg_dir),%eax
-	movl %eax,%cr3			/* cr3 - page directory start */
-	movl %cr0,%eax
-	orl $0x80000000,%eax
-	movl %eax,%cr0		/* set paging (PG) bit */
-	ret			/* this also flushes the prefetch-queue */
-
-/*
  * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x1000
- *
- * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
+ * 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.
  */
 .org 0x1000
 ENTRY(swapper_pg_dir)
+	.long 0x00102007
+	.fill 767,4,0
+	.long 0x00102007
+	.fill 127,4,0
+
 /*
  * The page tables are initialized to only 4MB here - the final page
- * tables are set up later depending on memory size.
+ * tables are set up later depending on memory size. The "007" at the
+ * end doesn't mean with right to kill, but PRESENT+RW+USER
  */
 .org 0x2000
 ENTRY(pg0)
+	.long 0x000007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+	.long 0x008007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+	.long 0x010007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+	.long 0x018007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+	.long 0x020007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+	.long 0x028007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+	.long 0x030007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+	.long 0x038007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+	.long 0x040007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+	.long 0x048007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+	.long 0x050007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+	.long 0x058007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+	.long 0x060007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+	.long 0x068007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+	.long 0x070007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+	.long 0x078007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+	.long 0x080007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+	.long 0x088007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+	.long 0x090007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+	.long 0x098007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+	.long 0x0a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+	.long 0x0a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+	.long 0x0b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+	.long 0x0b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+	.long 0x0c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+	.long 0x0c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+	.long 0x0d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+	.long 0x0d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+	.long 0x0e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+	.long 0x0e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+	.long 0x0f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+	.long 0x0f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
+	.long 0x100007,0x101007,0x102007,0x103007,0x104007,0x105007,0x106007,0x107007
+	.long 0x108007,0x109007,0x10a007,0x10b007,0x10c007,0x10d007,0x10e007,0x10f007
+	.long 0x110007,0x111007,0x112007,0x113007,0x114007,0x115007,0x116007,0x117007
+	.long 0x118007,0x119007,0x11a007,0x11b007,0x11c007,0x11d007,0x11e007,0x11f007
+	.long 0x120007,0x121007,0x122007,0x123007,0x124007,0x125007,0x126007,0x127007
+	.long 0x128007,0x129007,0x12a007,0x12b007,0x12c007,0x12d007,0x12e007,0x12f007
+	.long 0x130007,0x131007,0x132007,0x133007,0x134007,0x135007,0x136007,0x137007
+	.long 0x138007,0x139007,0x13a007,0x13b007,0x13c007,0x13d007,0x13e007,0x13f007
+	.long 0x140007,0x141007,0x142007,0x143007,0x144007,0x145007,0x146007,0x147007
+	.long 0x148007,0x149007,0x14a007,0x14b007,0x14c007,0x14d007,0x14e007,0x14f007
+	.long 0x150007,0x151007,0x152007,0x153007,0x154007,0x155007,0x156007,0x157007
+	.long 0x158007,0x159007,0x15a007,0x15b007,0x15c007,0x15d007,0x15e007,0x15f007
+	.long 0x160007,0x161007,0x162007,0x163007,0x164007,0x165007,0x166007,0x167007
+	.long 0x168007,0x169007,0x16a007,0x16b007,0x16c007,0x16d007,0x16e007,0x16f007
+	.long 0x170007,0x171007,0x172007,0x173007,0x174007,0x175007,0x176007,0x177007
+	.long 0x178007,0x179007,0x17a007,0x17b007,0x17c007,0x17d007,0x17e007,0x17f007
+	.long 0x180007,0x181007,0x182007,0x183007,0x184007,0x185007,0x186007,0x187007
+	.long 0x188007,0x189007,0x18a007,0x18b007,0x18c007,0x18d007,0x18e007,0x18f007
+	.long 0x190007,0x191007,0x192007,0x193007,0x194007,0x195007,0x196007,0x197007
+	.long 0x198007,0x199007,0x19a007,0x19b007,0x19c007,0x19d007,0x19e007,0x19f007
+	.long 0x1a0007,0x1a1007,0x1a2007,0x1a3007,0x1a4007,0x1a5007,0x1a6007,0x1a7007
+	.long 0x1a8007,0x1a9007,0x1aa007,0x1ab007,0x1ac007,0x1ad007,0x1ae007,0x1af007
+	.long 0x1b0007,0x1b1007,0x1b2007,0x1b3007,0x1b4007,0x1b5007,0x1b6007,0x1b7007
+	.long 0x1b8007,0x1b9007,0x1ba007,0x1bb007,0x1bc007,0x1bd007,0x1be007,0x1bf007
+	.long 0x1c0007,0x1c1007,0x1c2007,0x1c3007,0x1c4007,0x1c5007,0x1c6007,0x1c7007
+	.long 0x1c8007,0x1c9007,0x1ca007,0x1cb007,0x1cc007,0x1cd007,0x1ce007,0x1cf007
+	.long 0x1d0007,0x1d1007,0x1d2007,0x1d3007,0x1d4007,0x1d5007,0x1d6007,0x1d7007
+	.long 0x1d8007,0x1d9007,0x1da007,0x1db007,0x1dc007,0x1dd007,0x1de007,0x1df007
+	.long 0x1e0007,0x1e1007,0x1e2007,0x1e3007,0x1e4007,0x1e5007,0x1e6007,0x1e7007
+	.long 0x1e8007,0x1e9007,0x1ea007,0x1eb007,0x1ec007,0x1ed007,0x1ee007,0x1ef007
+	.long 0x1f0007,0x1f1007,0x1f2007,0x1f3007,0x1f4007,0x1f5007,0x1f6007,0x1f7007
+	.long 0x1f8007,0x1f9007,0x1fa007,0x1fb007,0x1fc007,0x1fd007,0x1fe007,0x1ff007
+	.long 0x200007,0x201007,0x202007,0x203007,0x204007,0x205007,0x206007,0x207007
+	.long 0x208007,0x209007,0x20a007,0x20b007,0x20c007,0x20d007,0x20e007,0x20f007
+	.long 0x210007,0x211007,0x212007,0x213007,0x214007,0x215007,0x216007,0x217007
+	.long 0x218007,0x219007,0x21a007,0x21b007,0x21c007,0x21d007,0x21e007,0x21f007
+	.long 0x220007,0x221007,0x222007,0x223007,0x224007,0x225007,0x226007,0x227007
+	.long 0x228007,0x229007,0x22a007,0x22b007,0x22c007,0x22d007,0x22e007,0x22f007
+	.long 0x230007,0x231007,0x232007,0x233007,0x234007,0x235007,0x236007,0x237007
+	.long 0x238007,0x239007,0x23a007,0x23b007,0x23c007,0x23d007,0x23e007,0x23f007
+	.long 0x240007,0x241007,0x242007,0x243007,0x244007,0x245007,0x246007,0x247007
+	.long 0x248007,0x249007,0x24a007,0x24b007,0x24c007,0x24d007,0x24e007,0x24f007
+	.long 0x250007,0x251007,0x252007,0x253007,0x254007,0x255007,0x256007,0x257007
+	.long 0x258007,0x259007,0x25a007,0x25b007,0x25c007,0x25d007,0x25e007,0x25f007
+	.long 0x260007,0x261007,0x262007,0x263007,0x264007,0x265007,0x266007,0x267007
+	.long 0x268007,0x269007,0x26a007,0x26b007,0x26c007,0x26d007,0x26e007,0x26f007
+	.long 0x270007,0x271007,0x272007,0x273007,0x274007,0x275007,0x276007,0x277007
+	.long 0x278007,0x279007,0x27a007,0x27b007,0x27c007,0x27d007,0x27e007,0x27f007
+	.long 0x280007,0x281007,0x282007,0x283007,0x284007,0x285007,0x286007,0x287007
+	.long 0x288007,0x289007,0x28a007,0x28b007,0x28c007,0x28d007,0x28e007,0x28f007
+	.long 0x290007,0x291007,0x292007,0x293007,0x294007,0x295007,0x296007,0x297007
+	.long 0x298007,0x299007,0x29a007,0x29b007,0x29c007,0x29d007,0x29e007,0x29f007
+	.long 0x2a0007,0x2a1007,0x2a2007,0x2a3007,0x2a4007,0x2a5007,0x2a6007,0x2a7007
+	.long 0x2a8007,0x2a9007,0x2aa007,0x2ab007,0x2ac007,0x2ad007,0x2ae007,0x2af007
+	.long 0x2b0007,0x2b1007,0x2b2007,0x2b3007,0x2b4007,0x2b5007,0x2b6007,0x2b7007
+	.long 0x2b8007,0x2b9007,0x2ba007,0x2bb007,0x2bc007,0x2bd007,0x2be007,0x2bf007
+	.long 0x2c0007,0x2c1007,0x2c2007,0x2c3007,0x2c4007,0x2c5007,0x2c6007,0x2c7007
+	.long 0x2c8007,0x2c9007,0x2ca007,0x2cb007,0x2cc007,0x2cd007,0x2ce007,0x2cf007
+	.long 0x2d0007,0x2d1007,0x2d2007,0x2d3007,0x2d4007,0x2d5007,0x2d6007,0x2d7007
+	.long 0x2d8007,0x2d9007,0x2da007,0x2db007,0x2dc007,0x2dd007,0x2de007,0x2df007
+	.long 0x2e0007,0x2e1007,0x2e2007,0x2e3007,0x2e4007,0x2e5007,0x2e6007,0x2e7007
+	.long 0x2e8007,0x2e9007,0x2ea007,0x2eb007,0x2ec007,0x2ed007,0x2ee007,0x2ef007
+	.long 0x2f0007,0x2f1007,0x2f2007,0x2f3007,0x2f4007,0x2f5007,0x2f6007,0x2f7007
+	.long 0x2f8007,0x2f9007,0x2fa007,0x2fb007,0x2fc007,0x2fd007,0x2fe007,0x2ff007
+	.long 0x300007,0x301007,0x302007,0x303007,0x304007,0x305007,0x306007,0x307007
+	.long 0x308007,0x309007,0x30a007,0x30b007,0x30c007,0x30d007,0x30e007,0x30f007
+	.long 0x310007,0x311007,0x312007,0x313007,0x314007,0x315007,0x316007,0x317007
+	.long 0x318007,0x319007,0x31a007,0x31b007,0x31c007,0x31d007,0x31e007,0x31f007
+	.long 0x320007,0x321007,0x322007,0x323007,0x324007,0x325007,0x326007,0x327007
+	.long 0x328007,0x329007,0x32a007,0x32b007,0x32c007,0x32d007,0x32e007,0x32f007
+	.long 0x330007,0x331007,0x332007,0x333007,0x334007,0x335007,0x336007,0x337007
+	.long 0x338007,0x339007,0x33a007,0x33b007,0x33c007,0x33d007,0x33e007,0x33f007
+	.long 0x340007,0x341007,0x342007,0x343007,0x344007,0x345007,0x346007,0x347007
+	.long 0x348007,0x349007,0x34a007,0x34b007,0x34c007,0x34d007,0x34e007,0x34f007
+	.long 0x350007,0x351007,0x352007,0x353007,0x354007,0x355007,0x356007,0x357007
+	.long 0x358007,0x359007,0x35a007,0x35b007,0x35c007,0x35d007,0x35e007,0x35f007
+	.long 0x360007,0x361007,0x362007,0x363007,0x364007,0x365007,0x366007,0x367007
+	.long 0x368007,0x369007,0x36a007,0x36b007,0x36c007,0x36d007,0x36e007,0x36f007
+	.long 0x370007,0x371007,0x372007,0x373007,0x374007,0x375007,0x376007,0x377007
+	.long 0x378007,0x379007,0x37a007,0x37b007,0x37c007,0x37d007,0x37e007,0x37f007
+	.long 0x380007,0x381007,0x382007,0x383007,0x384007,0x385007,0x386007,0x387007
+	.long 0x388007,0x389007,0x38a007,0x38b007,0x38c007,0x38d007,0x38e007,0x38f007
+	.long 0x390007,0x391007,0x392007,0x393007,0x394007,0x395007,0x396007,0x397007
+	.long 0x398007,0x399007,0x39a007,0x39b007,0x39c007,0x39d007,0x39e007,0x39f007
+	.long 0x3a0007,0x3a1007,0x3a2007,0x3a3007,0x3a4007,0x3a5007,0x3a6007,0x3a7007
+	.long 0x3a8007,0x3a9007,0x3aa007,0x3ab007,0x3ac007,0x3ad007,0x3ae007,0x3af007
+	.long 0x3b0007,0x3b1007,0x3b2007,0x3b3007,0x3b4007,0x3b5007,0x3b6007,0x3b7007
+	.long 0x3b8007,0x3b9007,0x3ba007,0x3bb007,0x3bc007,0x3bd007,0x3be007,0x3bf007
+	.long 0x3c0007,0x3c1007,0x3c2007,0x3c3007,0x3c4007,0x3c5007,0x3c6007,0x3c7007
+	.long 0x3c8007,0x3c9007,0x3ca007,0x3cb007,0x3cc007,0x3cd007,0x3ce007,0x3cf007
+	.long 0x3d0007,0x3d1007,0x3d2007,0x3d3007,0x3d4007,0x3d5007,0x3d6007,0x3d7007
+	.long 0x3d8007,0x3d9007,0x3da007,0x3db007,0x3dc007,0x3dd007,0x3de007,0x3df007
+	.long 0x3e0007,0x3e1007,0x3e2007,0x3e3007,0x3e4007,0x3e5007,0x3e6007,0x3e7007
+	.long 0x3e8007,0x3e9007,0x3ea007,0x3eb007,0x3ec007,0x3ed007,0x3ee007,0x3ef007
+	.long 0x3f0007,0x3f1007,0x3f2007,0x3f3007,0x3f4007,0x3f5007,0x3f6007,0x3f7007
+	.long 0x3f8007,0x3f9007,0x3fa007,0x3fb007,0x3fc007,0x3fd007,0x3fe007,0x3ff007
 
 .org 0x3000
 ENTRY(empty_bad_page)
@@ -376,7 +485,7 @@
 .word 0
 idt_descr:
 	.word 256*8-1		# idt contains 256 entries
-	.long 0xc0000000+SYMBOL_NAME(idt)
+	.long SYMBOL_NAME(idt)
 
 ENTRY(idt)
 	.fill 256,8,0		# idt is uninitialized
@@ -389,7 +498,7 @@
 #else
 	.word (8+2*NR_TASKS)*8-1
 #endif
-	.long 0xc0000000+SYMBOL_NAME(gdt)
+	.long SYMBOL_NAME(gdt)
 
 /*
  * This gdt setup gives the kernel a 1GB address space at virtual
@@ -398,8 +507,8 @@
 ENTRY(gdt)
 	.quad 0x0000000000000000	/* NULL descriptor */
 	.quad 0x0000000000000000	/* not used */
-	.quad 0xc0c39a000000ffff	/* 0x10 kernel 1GB code at 0xC0000000 */
-	.quad 0xc0c392000000ffff	/* 0x18 kernel 1GB data at 0xC0000000 */
+	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
+	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
 	.quad 0x00cbfa000000ffff	/* 0x23 user   3GB code at 0x00000000 */
 	.quad 0x00cbf2000000ffff	/* 0x2b user   3GB data at 0x00000000 */
 	.quad 0x0000000000000000	/* not used */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/ksyms.c	Sun Sep 15 10:34:18 1996
+++ linux/arch/i386/kernel/ksyms.c	Wed Sep 25 12:50:39 1996
@@ -4,6 +4,7 @@
 #include <linux/elfcore.h>
 
 #include <asm/semaphore.h>
+#include <asm/io.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
@@ -13,6 +14,7 @@
 	/* platform dependent support */
 	X(dump_thread),
 	X(dump_fpu),
+	X(ioremap),
 	XNOVERS(down_failed),
 	XNOVERS(up_wakeup),
 #ifdef __SMP__
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/ldt.c	Thu Mar  7 16:24:45 1996
+++ linux/arch/i386/kernel/ldt.c	Wed Sep 25 12:50:14 1996
@@ -8,9 +8,11 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/vmalloc.h>
+
 #include <asm/segment.h>
 #include <asm/system.h>
-#include <linux/ldt.h>
+#include <asm/ldt.h>
 
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/process.c	Wed Sep 11 17:57:13 1996
+++ linux/arch/i386/kernel/process.c	Wed Sep 25 12:53:02 1996
@@ -19,19 +19,20 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
+#include <linux/vmalloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
+#include <linux/smp.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <linux/smp.h>
+#include <asm/ldt.h>
 
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
 
@@ -182,6 +183,17 @@
  * and if it doesn't work, we do some other stupid things.
  */
 static long no_idt[2] = {0, 0};
+static int reboot_mode = 0;
+
+void reboot_setup(char *str, int *ints)
+{
+	int mode = 0;
+
+	/* "w" for "warm" reboot (no memory testing etc) */
+	if (str[0] == 'w')
+		mode = 0x1234;
+	reboot_mode = mode;
+}
 
 static inline void kb_wait(void)
 {
@@ -197,16 +209,14 @@
 	int i, j;
 
 	sti();
-/* rebooting needs to touch the page at absolute addr 0 */
-	pg0[0] = 7;
-	*((unsigned short *)0x472) = 0x1234;
+	*((unsigned short *)__va(0x472)) = reboot_mode;
 	for (;;) {
 		for (i=0; i<100; i++) {
 			kb_wait();
 			for(j = 0; j < 100000 ; j++)
 				/* nothing */;
 			outb(0xfe,0x64);	 /* pulse reset low */
-			udelay(10);
+			udelay(100);
 		}
 		__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
 	}
@@ -307,6 +317,7 @@
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
 	p->tss.esp = (unsigned long) childregs;
 	p->tss.eip = (unsigned long) ret_from_sys_call;
+	p->tss.ebx = (unsigned long) p;
 	*childregs = *regs;
 	childregs->eax = 0;
 	childregs->esp = esp;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/ptrace.c	Wed Sep 11 17:57:13 1996
+++ linux/arch/i386/kernel/ptrace.c	Mon Sep 23 14:39:39 1996
@@ -119,7 +119,7 @@
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page >= high_memory)
+	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 	page += addr & ~PAGE_MASK;
 	return *(unsigned long *) page;
@@ -174,7 +174,7 @@
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page < high_memory)
+	if (MAP_NR(page) < max_mapnr)
 		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/setup.c	Fri Sep 20 17:00:34 1996
+++ linux/arch/i386/kernel/setup.c	Mon Sep 30 09:37:53 1996
@@ -16,7 +16,6 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
@@ -140,10 +139,10 @@
 	if (!MOUNT_ROOT_RDONLY)
 		root_mountflags &= ~MS_RDONLY;
 	memory_start = (unsigned long) &_end;
-	init_task.mm->start_code = TASK_SIZE;
-	init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
-	init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
-	init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
+	init_task.mm->start_code = PAGE_OFFSET;
+	init_task.mm->end_code = (unsigned long) &_etext;
+	init_task.mm->end_data = (unsigned long) &_edata;
+	init_task.mm->brk = (unsigned long) &_end;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -180,13 +179,14 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
+	memory_end += PAGE_OFFSET;
 	*memory_start_p = memory_start;
 	*memory_end_p = memory_end;
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (LOADER_TYPE) {
-		initrd_start = INITRD_START;
-		initrd_end = INITRD_START+INITRD_SIZE;
+		initrd_start = INITRD_START + PAGE_OFFSET;
+		initrd_end = initrd_start+INITRD_SIZE;
 		if (initrd_end > memory_end) {
 			printk("initrd extends beyond end of memory "
 			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/signal.c	Tue Jul  2 19:08:34 1996
+++ linux/arch/i386/kernel/signal.c	Mon Sep 23 16:15:02 1996
@@ -197,7 +197,7 @@
 	put_user(regs->eflags, frame+18);
 	put_user(regs->esp, frame+19);
 	put_user(regs->ss, frame+20);
-	put_user(save_i387((struct _fpstate *)(frame+32)),frame+21);
+	put_user((unsigned long) save_i387((struct _fpstate *)(frame+32)),frame+21);
 /* non-iBCS2 extensions.. */
 	put_user(oldmask, frame+22);
 	put_user(current->tss.cr2, frame+23);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/smp.c	Mon May 13 07:17:23 1996
+++ linux/arch/i386/kernel/smp.c	Wed Sep 25 11:55:23 1996
@@ -67,7 +67,7 @@
 static volatile int smp_commenced=0;			/* Tripped when we start scheduling 		    	*/
 unsigned long apic_addr=0xFEE00000;			/* Address of APIC (defaults to 0xFEE00000)		*/
 unsigned long nlong = 0;				/* dummy used for apic_reg address + 0x20		*/
-unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the vremap() of the APIC 		*/
+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)		*/
 
@@ -619,7 +619,7 @@
 	 *	Map the local APIC into kernel space
 	 */
 
-	apic_reg = vremap(apic_addr,4096);
+	apic_reg = ioremap(apic_addr,4096);
 	
 	if(apic_reg == NULL)
 		panic("Unable to map local apic.\n");
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/traps.c	Mon Aug  5 10:13:50 1996
+++ linux/arch/i386/kernel/traps.c	Mon Sep 23 14:39:39 1996
@@ -134,7 +134,8 @@
 	printk("\nCall Trace: ");
 	stack = (unsigned long *) esp;
 	i = 1;
-	module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+	module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
+	module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
 	module_end = module_start + MODULE_RANGE;
 	while (((long) stack & 4095) != 0) {
 		addr = get_seg_long(ss, stack++);
@@ -329,7 +330,7 @@
 		return;
 	}
 	smptrap++;
-	if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0)
+	if (strncmp((char*)phys_to_virt(0x0FFFD9), "EISA", 4) == 0)
 		EISA_bus = 1;
 	set_call_gate(&default_ldt,lcall7);
 	set_trap_gate(0,&divide_error);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- lx2.0/v2.0.21/linux/arch/i386/kernel/vm86.c	Wed Apr  3 10:59:32 1996
+++ linux/arch/i386/kernel/vm86.c	Tue Sep 24 12:07:38 1996
@@ -102,10 +102,11 @@
 asmlinkage int sys_vm86(struct vm86_struct * v86)
 {
 	struct vm86_struct info;
+	struct task_struct *tsk = current;
 	struct pt_regs * pt_regs = (struct pt_regs *) &v86;
 	int error;
 
-	if (current->saved_kernel_stack)
+	if (tsk->saved_kernel_stack)
 		return -EPERM;
 	/* v86 must be readable (now) and writable (for save_v86_state) */
 	error = verify_area(VERIFY_WRITE,v86,sizeof(*v86));
@@ -131,16 +132,16 @@
 
 	switch (info.cpu_type) {
 		case CPU_286:
-			current->tss.v86mask = 0;
+			tsk->tss.v86mask = 0;
 			break;
 		case CPU_386:
-			current->tss.v86mask = NT_MASK | IOPL_MASK;
+			tsk->tss.v86mask = NT_MASK | IOPL_MASK;
 			break;
 		case CPU_486:
-			current->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+			tsk->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
 			break;
 		default:
-			current->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+			tsk->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
 			break;
 	}
 
@@ -148,17 +149,17 @@
  * Save old state, set default return value (%eax) to 0
  */
 	pt_regs->eax = 0;
-	current->saved_kernel_stack = current->tss.esp0;
-	current->tss.esp0 = (unsigned long) pt_regs;
-	current->tss.vm86_info = v86;
+	tsk->saved_kernel_stack = tsk->tss.esp0;
+	tsk->tss.esp0 = (unsigned long) pt_regs;
+	tsk->tss.vm86_info = v86;
 
-	current->tss.screen_bitmap = info.screen_bitmap;
+	tsk->tss.screen_bitmap = info.screen_bitmap;
 	if (info.flags & VM86_SCREEN_BITMAP)
-		mark_screen_rdonly(current);
+		mark_screen_rdonly(tsk);
 	__asm__ __volatile__("movl %0,%%esp\n\t"
 		"jmp ret_from_sys_call"
 		: /* no outputs */
-		:"r" (&info.regs));
+		:"r" (&info.regs), "b" (tsk));
 	return 0;
 }
 
@@ -170,7 +171,7 @@
 	regs32->eax = retval;
 	__asm__ __volatile__("movl %0,%%esp\n\t"
 		"jmp ret_from_sys_call"
-		: : "r" (regs32));
+		: : "r" (regs32), "b" (current));
 }
 
 static inline void set_IF(struct vm86_regs * regs)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- lx2.0/v2.0.21/linux/arch/i386/lib/checksum.c	Wed Sep 27 09:57:18 1995
+++ linux/arch/i386/lib/checksum.c	Mon Sep 23 11:26:30 1996
@@ -98,101 +98,6 @@
 
 
 /*
- * copy from fs while checksumming, otherwise like csum_partial
- */
-
-unsigned int csum_partial_copy_fromuser(const char *src, char *dst, 
-				  int len, int sum) {
-    __asm__("
-	testl $2, %%edi		# Check alignment.
-	jz 2f			# Jump if alignment is ok.
-	subl $2, %%ecx		# Alignment uses up two bytes.
-	jae 1f			# Jump if we had at least two bytes.
-	addl $2, %%ecx		# ecx was < 2.  Deal with it.
-	jmp 4f
-1:	movw %%fs:(%%esi), %%bx
-	addl $2, %%esi
-	movw %%bx, (%%edi)
-	addl $2, %%edi
-	addw %%bx, %%ax
-	adcl $0, %%eax
-2:
-	movl %%ecx, %%edx
-	shrl $5, %%ecx
-	jz 2f
-	testl %%esi, %%esi
-1:	movl %%fs:(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, (%%edi)
-
-	movl %%fs:4(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 4(%%edi)
-
-	movl %%fs:8(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 8(%%edi)
-
-	movl %%fs:12(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 12(%%edi)
-
-	movl %%fs:16(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 16(%%edi)
-
-	movl %%fs:20(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 20(%%edi)
-
-	movl %%fs:24(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 24(%%edi)
-
-	movl %%fs:28(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, 28(%%edi)
-
-	lea 32(%%esi), %%esi
-	lea 32(%%edi), %%edi
-	dec %%ecx
-	jne 1b
-	adcl $0, %%eax
-2:	movl %%edx, %%ecx
-	andl $28, %%edx
-	je 4f
-	shrl $2, %%edx
-	testl %%esi, %%esi
-3:	movl %%fs:(%%esi), %%ebx
-	adcl %%ebx, %%eax
-	movl %%ebx, (%%edi)
-	lea 4(%%esi), %%esi
-	lea 4(%%edi), %%edi
-	dec %%edx
-	jne 3b
-	adcl $0, %%eax
-4:	andl $3, %%ecx
-	jz 7f
-	cmpl $2, %%ecx
-	jb 5f
-	movw %%fs:(%%esi), %%cx
-	leal 2(%%esi), %%esi
-	movw %%cx, (%%edi)
-	leal 2(%%edi), %%edi
-	je 6f
-	shll $16,%%ecx
-5:	movb %%fs:(%%esi), %%cl
-	movb %%cl, (%%edi)
-6:	addl %%ecx, %%eax
-	adcl $0, %%eax
-7:
-	"
-	: "=a" (sum)
-	: "0"(sum), "c"(len), "S"(src), "D" (dst)
-	: "bx", "cx", "dx", "si", "di" );
-    return(sum);
-}
-/*
  * copy from ds while checksumming, otherwise like csum_partial
  */
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h
--- lx2.0/v2.0.21/linux/arch/i386/math-emu/fpu_emu.h	Thu May  9 07:59:33 1996
+++ linux/arch/i386/math-emu/fpu_emu.h	Sun Sep 22 10:11:43 1996
@@ -97,9 +97,9 @@
 
 struct address {
   unsigned int offset;
-  unsigned int selector:16;
-  unsigned int opcode:11;
-  unsigned int empty:5;
+  unsigned short selector;
+  unsigned short opcode:11,
+		 empty:5;
 };
 typedef void (*FUNC)(void);
 typedef struct fpu_reg FPU_REG;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile
--- lx2.0/v2.0.21/linux/arch/i386/mm/Makefile	Tue Aug 15 15:07:02 1995
+++ linux/arch/i386/mm/Makefile	Wed Sep 25 11:46:53 1996
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o
+O_OBJS	 := init.o fault.o ioremap.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- lx2.0/v2.0.21/linux/arch/i386/mm/fault.c	Wed Sep 11 17:57:13 1996
+++ linux/arch/i386/mm/fault.c	Mon Sep 23 10:28:23 1996
@@ -123,14 +123,14 @@
  *
  * First we check if it was the bootup rw-test, though..
  */
-	if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
+	if (wp_works_ok < 0 && !address && (error_code & 1)) {
 		wp_works_ok = 1;
 		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
 		flush_tlb();
 		printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
 		return;
 	}
-	if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
+	if (address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
 	} else
@@ -139,12 +139,12 @@
 	__asm__("movl %%cr3,%0" : "=r" (page));
 	printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
 		tsk->tss.cr3, page);
-	page = ((unsigned long *) page)[address >> 22];
+	page = ((unsigned long *) __va(page))[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {
 		page &= PAGE_MASK;
 		address &= 0x003ff000;
-		page = ((unsigned long *) page)[address >> PAGE_SHIFT];
+		page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
 		printk(KERN_ALERT "*pte = %08lx\n", page);
 	}
 	die_if_kernel("Oops", regs, error_code);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- lx2.0/v2.0.21/linux/arch/i386/mm/init.c	Sun Sep  8 19:50:20 1996
+++ linux/arch/i386/mm/init.c	Wed Sep 25 12:14:59 1996
@@ -81,7 +81,7 @@
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	i = high_memory >> PAGE_SHIFT;
+	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
 		if (PageReserved(mem_map+i))
@@ -149,8 +149,10 @@
 	wp_works_ok = 0;
 #endif
 	start_mem = PAGE_ALIGN(start_mem);
-	address = 0;
+	address = PAGE_OFFSET;
 	pg_dir = swapper_pg_dir;
+	/* unmap the original low memory mappings */
+	pgd_val(pg_dir[0]) = 0;
 	while (address < end_mem) {
 #ifdef USE_PENTIUM_MM
 		/*
@@ -172,29 +174,29 @@
 				: : :"ax");
 #endif
 			wp_works_ok = 1;
-			pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address;
-			pgd_val(pg_dir[768]) = _PAGE_TABLE | _PAGE_4M | address;
+			pgd_val(pg_dir[768]) = _PAGE_TABLE + _PAGE_4M + __pa(address);
 			pg_dir++;
 			address += 4*1024*1024;
 			continue;
 		}
 #endif
 		/* map the memory at virtual addr 0xC0000000 */
+		/* pg_table is physical at this point */
 		pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
 		if (!pg_table) {
-			pg_table = (pte_t *) start_mem;
+			pg_table = (pte_t *) __pa(start_mem);
 			start_mem += PAGE_SIZE;
 		}
 
-		/* also map it temporarily at 0x0000000 for init */
-		pgd_val(pg_dir[0])   = _PAGE_TABLE | (unsigned long) pg_table;
 		pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
 		pg_dir++;
+		/* now change pg_table to kernel virtual addresses */
+		pg_table = (pte_t *) __va(pg_table);
 		for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
-			if (address < end_mem)
-				set_pte(pg_table, mk_pte(address, PAGE_SHARED));
-			else
-				pte_clear(pg_table);
+			pte_t pte = mk_pte(address, PAGE_KERNEL);
+			if (address >= end_mem)
+				pte_val(pte) = 0;
+			set_pte(pg_table, pte);
 			address += PAGE_SIZE;
 		}
 	}
@@ -212,13 +214,14 @@
 	extern int _etext;
 
 	end_mem &= PAGE_MASK;
-	high_memory = end_mem;
+	high_memory = (void *) end_mem;
+	max_mapnr = MAP_NR(end_mem);
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
 
 	/* mark usable pages in the mem_map[] */
-	start_low_mem = PAGE_ALIGN(start_low_mem);
+	start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET;
 
 #ifdef __SMP__
 	/*
@@ -234,20 +237,20 @@
 	 * They seem to have done something stupid with the floppy
 	 * controller as well..
 	 */
-	while (start_low_mem < 0x9f000) {
+	while (start_low_mem < 0x9f000+PAGE_OFFSET) {
 		clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
 		start_low_mem += PAGE_SIZE;
 	}
 
-	while (start_mem < high_memory) {
+	while (start_mem < end_mem) {
 		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
 		start_mem += PAGE_SIZE;
 	}
-	for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
+	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
-			if (tmp >= 0xA0000 && tmp < 0x100000)
+			if (tmp >= 0xA0000+PAGE_OFFSET && tmp < 0x100000+PAGE_OFFSET)
 				reservedpages++;
 			else if (tmp < (unsigned long) &_etext)
 				codepages++;
@@ -262,19 +265,24 @@
 #endif
 			free_page(tmp);
 	}
-	tmp = nr_free_pages << PAGE_SHIFT;
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
-		tmp >> 10,
-		high_memory >> 10,
+		(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+		max_mapnr << (PAGE_SHIFT-10),
 		codepages << (PAGE_SHIFT-10),
 		reservedpages << (PAGE_SHIFT-10),
 		datapages << (PAGE_SHIFT-10));
 /* test if the WP bit is honoured in supervisor mode */
 	if (wp_works_ok < 0) {
-		pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
+		unsigned char tmp_reg;
+		pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
 		local_flush_tlb();
-		__asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory");
-		pg0[0] = 0;
+		__asm__ __volatile__(
+			"movb %0,%1 ; movb %1,%0"
+			:"=m" (*(char *) __va(0)),
+			 "=q" (tmp_reg)
+			:/* no inputs */
+			:"memory");
+		pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL));
 		local_flush_tlb();
 		if (wp_works_ok < 0)
 			wp_works_ok = 0;
@@ -286,7 +294,7 @@
 {
 	int i;
 
-	i = high_memory >> PAGE_SHIFT;
+	i = max_mapnr;
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c
--- lx2.0/v2.0.21/linux/arch/i386/mm/ioremap.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/i386/mm/ioremap.c	Wed Sep 25 12:12:50 1996
@@ -0,0 +1,109 @@
+/*
+ * arch/i386/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ */
+
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		if (!pte_none(*pte))
+			printk("remap_area_pte: page already exists\n");
+		set_pte(pte, mk_pte_phys(phys_addr, PAGE_KERNEL));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	do {
+		pte_t * pte = pte_alloc_kernel(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	while (address < end) {
+		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (remap_area_pmd(pmd, address, end - address, phys_addr + address))
+			return -ENOMEM;
+		set_pgdir(address, *dir);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_all();
+	return 0;
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ */
+void * ioremap(unsigned long phys_addr, unsigned long size)
+{
+	void * addr;
+	struct vm_struct * area;
+
+	if (phys_addr < virt_to_phys(high_memory))
+		return phys_to_virt(phys_addr);
+	if (phys_addr & ~PAGE_MASK)
+		return NULL;
+	size = PAGE_ALIGN(size);
+	if (!size || size > phys_addr + size)
+		return NULL;
+	area = get_vm_area(size);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size)) {
+		vfree(addr);
+		return NULL;
+	}
+	return addr;
+}
+
+void iounmap(void *addr)
+{
+	if (addr > high_memory)
+		return vfree(addr);
+}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/Makefile	Sat Mar 23 16:41:07 1996
+++ linux/arch/m68k/Makefile	Wed Sep 25 10:47:37 1996
@@ -21,7 +21,7 @@
 # set up for cross compiling
 COMPILE_ARCH = $(shell uname -m)
 ifneq ($(COMPILE_ARCH),$(ARCH))
-	CROSSDIR=/usr/$(ARCH)-linux
+	CROSSDIR=/usr/$(ARCH)-linux/bin
 	CC := $(CROSSDIR)/$(CC)
 	AS := $(CROSSDIR)/$(AS)
 	LD := $(CROSSDIR)/$(LD)
@@ -50,12 +50,16 @@
 else
 LINKFLAGS = -qmagic -Ttext 0xFE0
 endif
+
 CFLAGS := $(CFLAGS) -pipe
 
+ifdef CONFIG_OPTIMIZE_040
+CFLAGS := $(CFLAGS) -m68040
+endif
+
 HEAD := arch/m68k/kernel/head.o
 
 SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/console arch/m68k/lib
-#SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib
 ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES)
 LIBS += arch/m68k/lib/lib.a
 
@@ -77,12 +81,12 @@
 # add in console.a after {amiga,atari}.o that need it
 ARCHIVES := $(ARCHIVES) arch/m68k/console/console.a
 
-ifdef CONFIG_FPSP_040
+ifdef CONFIG_M68040
 ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
 endif
 
-ifdef CONFIG_IFPSP_060
+ifdef CONFIG_M68060
 ARCHIVES := $(ARCHIVES) arch/m68k/ifpsp060/ifpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
 endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/Makefile_elf linux/arch/m68k/Makefile_elf
--- lx2.0/v2.0.21/linux/arch/m68k/Makefile_elf	Wed Dec 27 22:51:18 1995
+++ linux/arch/m68k/Makefile_elf	Thu Jan  1 02:00:00 1970
@@ -1,91 +0,0 @@
-#
-# m68k/Makefile
-#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
-# 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.
-#
-# Copyright (C) 1994 by Hamish Macdonald
-#
-
-# override top level makefile
-AS	= as -m68020 
-#CC	:= $(CC) -b m68kelf
-LD	= ld -m m68kelf
-
-
-#
-# 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 = -qmagic -Ttext 0xFE0
-
-HEAD := arch/m68k/kernel/head.o
-
-SUBDIRS := $(SUBDIRS) arch/m68k/kernel arch/m68k/mm arch/m68k/lib
-ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES)
-LIBS := $(TOPDIR)/arch/m68k/lib/lib.a $(LIBS) $(TOPDIR)/arch/m68k/lib/lib.a
-
-ifdef CONFIG_AMIGA
-ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o
-SUBDIRS := $(SUBDIRS) arch/m68k/amiga
-endif
-
-ifdef CONFIG_ATARI
-ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o
-SUBDIRS := $(SUBDIRS) arch/m68k/atari
-endif
-
-ifdef CONFIG_MAC
-ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o
-SUBDIRS := $(SUBDIRS) arch/m68k/mac
-endif
-
-ifdef CONFIG_FPSP_040
-ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o
-SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
-endif
-
-arch/m68k/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/kernel
-
-arch/m68k/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/mm
-
-arch/m68k/lib: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/lib
-
-arch/m68k/amiga: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/amiga
-
-arch/m68k/atari: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/atari
-
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
-lilo:	vmlinux
-	if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
-	if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
-	cat vmlinux > $(INSTALL_PATH)/vmlinux
-	cp System.map $(INSTALL_PATH)/System.map
-	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
-
-bootstrap:
-	@$(MAKEBOOT) bootstrap
-
-archclean:
-	@$(MAKEBOOT) clean
-
-archdep:
-	$(MAKEBOOT) dep
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/Makefile	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/Makefile	Wed Sep 25 10:47:37 1996
@@ -8,9 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := amiga.o
-O_OBJS	 := config.o amikeyb.o amiints.o \
-	   chipram.o amisound.o amifb.o zorro.o
-OX_OBJS = ksyms.o
+O_OBJS   := config.o amikeyb.o amiints.o cia.o \
+            chipram.o amisound.o amifb.o zorro.o ksyms.o
 
 ifdef CONFIG_FB_CYBER
 O_OBJS := $(O_OBJS) cyberfb.o
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/amifb.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/amifb.c	Wed Sep 25 10:47:37 1996
@@ -4,6 +4,8 @@
  *
  *    Copyright (C) 1995 Geert Uytterhoeven
  *
+ *          with work by Roman Zippel
+ *
  *
  * This file is based on the Atari frame buffer device (atafb.c):
  *
@@ -26,15 +28,19 @@
  *
  * History:
  *
+ *   - 24 Jul 96: Copper generates now vblank interrupt and
+ *                VESA Power Saving Protocol is fully implemented
+ *   - 14 Jul 96: Rework and hopefully last ECS bugs fixed
+ *   -  7 Mar 96: Hardware sprite support by Roman Zippel
+ *   - 18 Feb 96: OCS and ECS support by Roman Zippel
+ *                Hardware functions completely rewritten
  *   -  2 Dec 95: AGA version by 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
+ * 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>
@@ -44,38 +50,46 @@
 #include <linux/delay.h>
 #include <linux/config.h>
 #include <linux/interrupt.h>
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
-#include <asm/bootinfo.h>
 #include <linux/fb.h>
 
+#define DEBUG
 
-#undef  CONFIG_AMIFB_OCS
-#undef  CONFIG_AMIFB_ECS
-#define CONFIG_AMIFB_AGA   /* Only AGA support at the moment */
-
-#define USE_MONO_AMIFB_IF_NON_AGA
-
-
-/* -------------------- BEGIN: TODO ----------------------------------------- **
-
-
-   - scan the sources for `TODO'
-
-   - timings and monspecs can be set via the kernel command line (cfr. Atari)
-
-   - OCS and ECS
-
-   - hardware cursor
-
-   - Interlaced screen -> Interlaced sprite/hardware cursor
+#if !defined(CONFIG_AMIFB_OCS) && !defined(CONFIG_AMIFB_ECS) && !defined(CONFIG_AMIFB_AGA)
+#define CONFIG_AMIFB_OCS   /* define at least one fb driver, this will change later */
+#endif
 
+#if !defined(CONFIG_AMIFB_OCS)
+#  define IS_OCS (0)
+#elif defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
+#  define IS_OCS (chipset == TAG_OCS)
+#else
+#  define CONFIG_AMIFB_OCS_ONLY
+#  define IS_OCS (1)
+#endif
 
-** -------------------- END: TODO ------------------------------------------- */
+#if !defined(CONFIG_AMIFB_ECS)
+#  define IS_ECS (0)
+#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_AGA)
+#  define IS_ECS (chipset == TAG_ECS)
+#else
+#  define CONFIG_AMIFB_ECS_ONLY
+#  define IS_ECS (1)
+#endif
 
+#if !defined(CONFIG_AMIFB_AGA)
+#  define IS_AGA (0)
+#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_ECS)
+#  define IS_AGA (chipset == TAG_AGA)
+#else
+#  define CONFIG_AMIFB_AGA_ONLY
+#  define IS_AGA (1)
+#endif
 
 /*******************************************************************************
 
@@ -184,15 +198,15 @@
    -------------------------------------------
 
    Since there are much more parameters for the Amiga display than for the
-   frame buffer interface, there must be some dependencies among the Amiga display
-   parameters. Here's what I found out:
+   frame buffer interface, there must be some dependencies among the Amiga
+   display parameters. Here's what I found out:
 
       - ddfstrt and ddfstop are best aligned to 64 pixels.
       - the chipset needs 64+4 horizontal pixels after the DMA start before the
         first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
         display the first pixel on the line too. Increase diwstrt_h for virtual
         screen panning.
-      - the display DMA always fetches 64 pixels at a time (*).
+      - the display DMA always fetches 64 pixels at a time (fmode = 3).
       - ddfstop is ddfstrt+#pixels-64.
       - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
         more than htotal.
@@ -205,10 +219,37 @@
         cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
       - I make diwstop_h and diwstop_v as large as possible.
 
-   (*) This is for fmode = 3. Lower fmodes allow for more freedom w.r.t. the
-       timings, but they limit the maximum display depth, and cause more stress
-       on the custom chip bus.
+   General dependencies
+   --------------------
+
+      - all values are SHRES pixel (35ns)
 
+                  table 1:fetchstart  table 2:prefetch    table 3:fetchsize
+                  ------------------  ----------------    -----------------
+   Pixclock     # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
+   -------------#------+-----+------#------+-----+------#------+-----+------
+   Bus width 1x #   16 |  32 |  64  #   16 |  32 |  64  #   64 |  64 |  64
+   Bus width 2x #   32 |  64 | 128  #   32 |  64 |  64  #   64 |  64 | 128
+   Bus width 4x #   64 | 128 | 256  #   64 |  64 |  64  #   64 | 128 | 256
+
+      - chipset needs 4 pixels before the first pixel is output
+      - ddfstrt must be aligned to fetchstart (table 1)
+      - chipset needs also prefetch (table 2) to get first pixel data, so
+        ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
+      - for horizontal panning decrease diwstrt_h
+      - the length of a fetchline must be aligned to fetchsize (table 3)
+      - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
+        moved to optimize use of dma (usefull for OCS/ECS overscan displays)
+      - ddfstop is ddfstrt+ddfsize-fetchsize
+      - If C= didn't change anything for AGA, then at following positions the
+        dma bus is allready used:
+        ddfstrt <  48 -> memory refresh
+                <  96 -> disk dma
+                < 160 -> audio dma
+                < 192 -> sprite 0 dma
+                < 416 -> sprite dma (32 per sprite)
+      - in accordance with the hardware reference manual a hardware stop is at
+        192, but AGA (ECS?) can go below this.
 
    DMA priorities
    --------------
@@ -228,7 +269,7 @@
    Implementation
    --------------
 
-   aga_decode_var() converts the frame buffer values to the Amiga values. It's
+   ami_decode_var() converts the frame buffer values to the Amiga values. It's
    just a `straightforward' implementation of the above rules.
 
 
@@ -269,11 +310,6 @@
    Broadcast video timings
    -----------------------
 
-   Since broadcast video timings are `fixed' and only depend on the video
-   system (PAL/NTSC), hsync_len and vsync_len are not used and must be set to
-   zero. All xres/yres and margin values are defined within the `visible
-   rectangle' of the display.
-
    According to the CCIR and RETMA specifications, we have the following values:
 
    CCIR -> PAL
@@ -296,17 +332,23 @@
 
       - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
         timings are to be used.
-      - make sure upper_margin+yres+lower_margin = 576 for an interlaced, 288
-        for a non-interlaced and 144 for a doublescanned display.
-      - make sure (left_margin+xres+right_margin)*pixclock is a reasonable
-        approximation to 52.48 µs.
+      - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
+        interlaced, 312 for a non-interlaced and 156 for a doublescanned
+        display.
+      - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
+        908 for a HIRES and 454 for a LORES display.
+      - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
+        left_margin+2*hsync_len must be greater or equal.
+      - the upper visible part begins at 48 (interlaced; non-interlaced:24,
+        doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
+      - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
+        of 4 scanlines
 
    The settings for a NTSC compatible display are straightforward.
 
    Note that in a strict sense the PAL and NTSC standards only define the
    encoding of the color part (chrominance) of the video signal and don't say
    anything about horizontal/vertical synchronization nor refresh rates.
-   But since Amigas have RGB output, this issue isn't of any importance here.
 
 
                                                             -- Geert --
@@ -314,4792 +356,3228 @@
 *******************************************************************************/
 
 
-   /*
-    *    Custom Chipset Definitions
-    */
+	/*
+	 * Custom Chipset Definitions
+	 */
 
 #define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
 
+	/*
+	 * BPLCON0 -- Bitplane Control Register 0
+	 */
 
-   /*
-    *    BPLCON0 -- Bitplane Control Register 0
-    */
-
-#define BPC0_HIRES      (0x8000)
-#define BPC0_BPU2       (0x4000) /* Bit plane used count */
-#define BPC0_BPU1       (0x2000)
-#define BPC0_BPU0       (0x1000)
-#define BPC0_HAM        (0x0800) /* HAM mode */
-#define BPC0_DPF        (0x0400) /* Double playfield */
-#define BPC0_COLOR      (0x0200) /* Enable colorburst */
-#define BPC0_GAUD       (0x0100) /* Genlock audio enable */
-#define BPC0_UHRES      (0x0080) /* Ultrahi res enable */
-#define BPC0_SHRES      (0x0040) /* Super hi res mode */
-#define BPC0_BYPASS     (0x0020) /* Bypass LUT - AGA */
-#define BPC0_BPU3       (0x0010) /* AGA */
-#define BPC0_LPEN       (0x0008) /* Light pen enable */
-#define BPC0_LACE       (0x0004) /* Interlace */
-#define BPC0_ERSY       (0x0002) /* External resync */
-#define BPC0_ECSENA     (0x0001) /* ECS emulation disable */
-
-
-   /*
-    *    BPLCON2 -- Bitplane Control Register 2
-    */
-
-#define BPC2_ZDBPSEL2   (0x4000) /* Bitplane to be used for ZD - AGA */
-#define BPC2_ZDBPSEL1   (0x2000)
-#define BPC2_ZDBPSEL0   (0x1000)
-#define BPC2_ZDBPEN     (0x0800) /* Enable ZD with ZDBPSELx - AGA */
-#define BPC2_ZDCTEN     (0x0400) /* Enable ZD with palette bit #31 - AGA */
-#define BPC2_KILLEHB    (0x0200) /* Kill EHB mode - AGA */
-#define BPC2_RDRAM      (0x0100) /* Color table accesses read, not write - AGA */
-#define BPC2_SOGEN      (0x0080) /* SOG output pin high - AGA */
-#define BPC2_PF2PRI     (0x0040) /* PF2 priority over PF1 */
-#define BPC2_PF2P2      (0x0020) /* PF2 priority wrt sprites */
-#define BPC2_PF2P1      (0x0010)
-#define BPC2_PF2P0      (0x0008)
-#define BPC2_PF1P2      (0x0004) /* ditto PF1 */
-#define BPC2_PF1P1      (0x0002)
-#define BPC2_PF1P0      (0x0001)
-
-
-   /*
-    *    BPLCON3 -- Bitplane Control Register 3 (AGA)
-    */
-
-#define BPC3_BANK2      (0x8000) /* Bits to select color register bank */
-#define BPC3_BANK1      (0x4000)
-#define BPC3_BANK0      (0x2000)
-#define BPC3_PF2OF2     (0x1000) /* Bits for color table offset when PF2 */
-#define BPC3_PF2OF1     (0x0800)
-#define BPC3_PF2OF0     (0x0400)
-#define BPC3_LOCT       (0x0200) /* Color register writes go to low bits */
-#define BPC3_SPRES1     (0x0080) /* Sprite resolution bits */
-#define BPC3_SPRES0     (0x0040)
-#define BPC3_BRDRBLNK   (0x0020) /* Border blanked? */
-#define BPC3_BRDRTRAN   (0x0010) /* Border transparent? */
-#define BPC3_ZDCLKEN    (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
-#define BPC3_BRDRSPRT   (0x0002) /* Sprites in border? */
-#define BPC3_EXTBLKEN   (0x0001) /* BLANK programmable */
-
-
-   /*
-    *    BPLCON4 -- Bitplane Control Register 4 (AGA)
-    */
-
-#define BPC4_BPLAM7     (0x8000) /* bitplane color XOR field */
-#define BPC4_BPLAM6     (0x4000)
-#define BPC4_BPLAM5     (0x2000)
-#define BPC4_BPLAM4     (0x1000)
-#define BPC4_BPLAM3     (0x0800)
-#define BPC4_BPLAM2     (0x0400)
-#define BPC4_BPLAM1     (0x0200)
-#define BPC4_BPLAM0     (0x0100)
-#define BPC4_ESPRM7     (0x0080) /* 4 high bits for even sprite colors */
-#define BPC4_ESPRM6     (0x0040)
-#define BPC4_ESPRM5     (0x0020)
-#define BPC4_ESPRM4     (0x0010)
-#define BPC4_OSPRM7     (0x0008) /* 4 high bits for odd sprite colors */
-#define BPC4_OSPRM6     (0x0004)
-#define BPC4_OSPRM5     (0x0002)
-#define BPC4_OSPRM4     (0x0001)
-
-
-   /*
-    *    BEAMCON0 -- Beam Control Register
-    */
-
-#define BMC0_HARDDIS    (0x4000) /* Disable hardware limits */
-#define BMC0_LPENDIS    (0x2000) /* Disable light pen latch */
-#define BMC0_VARVBEN    (0x1000) /* Enable variable vertical blank */
-#define BMC0_LOLDIS     (0x0800) /* Disable long/short line toggle */
-#define BMC0_CSCBEN     (0x0400) /* Composite sync/blank */
-#define BMC0_VARVSYEN   (0x0200) /* Enable variable vertical sync */
-#define BMC0_VARHSYEN   (0x0100) /* Enable variable horizontal sync */
-#define BMC0_VARBEAMEN  (0x0080) /* Enable variable beam counters */
-#define BMC0_DUAL       (0x0080) /* Enable alternate horizontal beam counter */
-#define BMC0_PAL        (0x0020) /* Set decodes for PAL */
-#define BMC0_VARCSYEN   (0x0010) /* Enable variable composite sync */
-#define BMC0_BLANKEN    (0x0008) /* Blank enable (no longer used on AGA) */
-#define BMC0_CSYTRUE    (0x0004) /* CSY polarity */
-#define BMC0_VSYTRUE    (0x0002) /* VSY polarity */
-#define BMC0_HSYTRUE    (0x0001) /* HSY polarity */
-
-
-   /*
-    *    FMODE -- Fetch Mode Control Register (AGA)
-    */
-
-#define FMODE_SSCAN2    (0x8000) /* Sprite scan-doubling */
-#define FMODE_BSCAN2    (0x4000) /* Use PF2 modulus every other line */
-#define FMODE_SPAGEM    (0x0008) /* Sprite page mode */
-#define FMODE_SPR32     (0x0004) /* Sprite 32 bit fetch */
-#define FMODE_BPAGEM    (0x0002) /* Bitplane page mode */
-#define FMODE_BPL32     (0x0001) /* Bitplane 32 bit fetch */
-
-
-   /*
-    *    Tags used to indicate a specific Pixel Clock
-    *
-    *    clk_shift is the shift value to get the timings in 35 ns units
-    */
-
-#define TAG_SHRES       (1)      /* SHRES, clk_shift = TAG_SHRES-1 */
-#define TAG_HIRES       (2)      /* HIRES, clk_shift = TAG_HIRES-1 */
-#define TAG_LORES       (3)      /* LORES, clk_shift = TAG_LORES-1 */
-
-
-   /*
-    *    Clock Definitions, Maximum Display Depth
-    *
-    *    These depend on the E-Clock or the Chipset, so they are filled in
-    *    dynamically
-    */
-
-static u_long pixclock[3];       /* SHRES/HIRES/LORES: index = clk_shift */
-static u_short maxdepth[3];      /* SHRES/HIRES/LORES: index = clk_shift */
-
-
-   /*
-    *    Broadcast Video Timings
-    *
-    *    Horizontal values are in 35 ns (SHRES) units
-    *    Vertical values are in non-interlaced scanlines
-    */
-
-#define PAL_WINDOW_H    (1472)   /* PAL Window Limits */
-#define PAL_WINDOW_V    (288)
-#define PAL_DIWSTRT_H   (360)
-#define PAL_DIWSTRT_V   (24)
-
-#define NTSC_WINDOW_H   (1472)   /* NTSC Window Limits */
-#define NTSC_WINDOW_V   (242)
-#define NTSC_DIWSTRT_H  (360)
-#define NTSC_DIWSTRT_V  (20)
-
-#define PAL_HTOTAL      (1816)   /* Total line length */
-#define NTSC_HTOTAL     (1816)   /* Needed for YWRAP */
-
-
-   /*
-    *    Monitor Specifications
-    *
-    *    These are typical for a `generic' Amiga monitor (e.g. A1960)
-    */
+#define BPC0_HIRES	(0x8000)
+#define BPC0_BPU2	(0x4000) /* Bit plane used count */
+#define BPC0_BPU1	(0x2000)
+#define BPC0_BPU0	(0x1000)
+#define BPC0_HAM	(0x0800) /* HAM mode */
+#define BPC0_DPF	(0x0400) /* Double playfield */
+#define BPC0_COLOR	(0x0200) /* Enable colorburst */
+#define BPC0_GAUD	(0x0100) /* Genlock audio enable */
+#define BPC0_UHRES	(0x0080) /* Ultrahi res enable */
+#define BPC0_SHRES	(0x0040) /* Super hi res mode */
+#define BPC0_BYPASS	(0x0020) /* Bypass LUT - AGA */
+#define BPC0_BPU3	(0x0010) /* AGA */
+#define BPC0_LPEN	(0x0008) /* Light pen enable */
+#define BPC0_LACE	(0x0004) /* Interlace */
+#define BPC0_ERSY	(0x0002) /* External resync */
+#define BPC0_ECSENA	(0x0001) /* ECS enable */
 
-static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
+	/*
+	 * BPLCON2 -- Bitplane Control Register 2
+	 */
 
-static u_short pwrsave = 0;      /* VESA suspend mode (not for PAL/NTSC) */
+#define BPC2_ZDBPSEL2	(0x4000) /* Bitplane to be used for ZD - AGA */
+#define BPC2_ZDBPSEL1	(0x2000)
+#define BPC2_ZDBPSEL0	(0x1000)
+#define BPC2_ZDBPEN	(0x0800) /* Enable ZD with ZDBPSELx - AGA */
+#define BPC2_ZDCTEN	(0x0400) /* Enable ZD with palette bit #31 - AGA */
+#define BPC2_KILLEHB	(0x0200) /* Kill EHB mode - AGA */
+#define BPC2_RDRAM	(0x0100) /* Color table accesses read, not write - AGA */
+#define BPC2_SOGEN	(0x0080) /* SOG output pin high - AGA */
+#define BPC2_PF2PRI	(0x0040) /* PF2 priority over PF1 */
+#define BPC2_PF2P2	(0x0020) /* PF2 priority wrt sprites */
+#define BPC2_PF2P1	(0x0010)
+#define BPC2_PF2P0	(0x0008)
+#define BPC2_PF1P2	(0x0004) /* ditto PF1 */
+#define BPC2_PF1P1	(0x0002)
+#define BPC2_PF1P0	(0x0001)
 
+	/*
+	 * BPLCON3 -- Bitplane Control Register 3 (AGA)
+	 */
 
-   /*
-    *    Various macros
-    */
+#define BPC3_BANK2	(0x8000) /* Bits to select color register bank */
+#define BPC3_BANK1	(0x4000)
+#define BPC3_BANK0	(0x2000)
+#define BPC3_PF2OF2	(0x1000) /* Bits for color table offset when PF2 */
+#define BPC3_PF2OF1	(0x0800)
+#define BPC3_PF2OF0	(0x0400)
+#define BPC3_LOCT	(0x0200) /* Color register writes go to low bits */
+#define BPC3_SPRES1	(0x0080) /* Sprite resolution bits */
+#define BPC3_SPRES0	(0x0040)
+#define BPC3_BRDRBLNK	(0x0020) /* Border blanked? */
+#define BPC3_BRDRTRAN	(0x0010) /* Border transparent? */
+#define BPC3_ZDCLKEN	(0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
+#define BPC3_BRDRSPRT	(0x0002) /* Sprites in border? */
+#define BPC3_EXTBLKEN	(0x0001) /* BLANK programmable */
 
-#define up8(x)          (((x)+7) & ~7)
-#define down8(x)        ((x) & ~7)
-#define div8(x)         ((x)>>3)
-#define mod8(x)         ((x) & 7)
+	/*
+	 * BPLCON4 -- Bitplane Control Register 4 (AGA)
+	 */
 
-#define up16(x)         (((x)+15) & ~15)
-#define down16(x)       ((x) & ~15)
-#define div16(x)        ((x)>>4)
-#define mod16(x)        ((x) & 15)
+#define BPC4_BPLAM7	(0x8000) /* bitplane color XOR field */
+#define BPC4_BPLAM6	(0x4000)
+#define BPC4_BPLAM5	(0x2000)
+#define BPC4_BPLAM4	(0x1000)
+#define BPC4_BPLAM3	(0x0800)
+#define BPC4_BPLAM2	(0x0400)
+#define BPC4_BPLAM1	(0x0200)
+#define BPC4_BPLAM0	(0x0100)
+#define BPC4_ESPRM7	(0x0080) /* 4 high bits for even sprite colors */
+#define BPC4_ESPRM6	(0x0040)
+#define BPC4_ESPRM5	(0x0020)
+#define BPC4_ESPRM4	(0x0010)
+#define BPC4_OSPRM7	(0x0008) /* 4 high bits for odd sprite colors */
+#define BPC4_OSPRM6	(0x0004)
+#define BPC4_OSPRM5	(0x0002)
+#define BPC4_OSPRM4	(0x0001)
 
-#define up32(x)         (((x)+31) & ~31)
-#define down32(x)       ((x) & ~31)
-#define div32(x)        ((x)>>5)
-#define mod32(x)        ((x) & 31)
+	/*
+	 * BEAMCON0 -- Beam Control Register
+	 */
 
-#define up64(x)         (((x)+63) & ~63)
-#define down64(x)       ((x) & ~63)
-#define div64(x)        ((x)>>6)
-#define mod64(x)        ((x) & 63)
+#define BMC0_HARDDIS	(0x4000) /* Disable hardware limits */
+#define BMC0_LPENDIS	(0x2000) /* Disable light pen latch */
+#define BMC0_VARVBEN	(0x1000) /* Enable variable vertical blank */
+#define BMC0_LOLDIS	(0x0800) /* Disable long/short line toggle */
+#define BMC0_CSCBEN	(0x0400) /* Composite sync/blank */
+#define BMC0_VARVSYEN	(0x0200) /* Enable variable vertical sync */
+#define BMC0_VARHSYEN	(0x0100) /* Enable variable horizontal sync */
+#define BMC0_VARBEAMEN	(0x0080) /* Enable variable beam counters */
+#define BMC0_DUAL	(0x0040) /* Enable alternate horizontal beam counter */
+#define BMC0_PAL	(0x0020) /* Set decodes for PAL */
+#define BMC0_VARCSYEN	(0x0010) /* Enable variable composite sync */
+#define BMC0_BLANKEN	(0x0008) /* Blank enable (no longer used on AGA) */
+#define BMC0_CSYTRUE	(0x0004) /* CSY polarity */
+#define BMC0_VSYTRUE	(0x0002) /* VSY polarity */
+#define BMC0_HSYTRUE	(0x0001) /* HSY polarity */
 
-#define min(a, b)       ((a) < (b) ? (a) : (b))
-#define max(a, b)       ((a) > (b) ? (a) : (b))
 
-#define highw(x)        ((u_long)(x)>>16 & 0xffff)
-#define loww(x)         ((u_long)(x) & 0xffff)
+	/*
+	 * FMODE -- Fetch Mode Control Register (AGA)
+	 */
 
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+#define FMODE_SSCAN2	(0x8000) /* Sprite scan-doubling */
+#define FMODE_BSCAN2	(0x4000) /* Use PF2 modulus every other line */
+#define FMODE_SPAGEM	(0x0008) /* Sprite page mode */
+#define FMODE_SPR32	(0x0004) /* Sprite 32 bit fetch */
+#define FMODE_BPAGEM	(0x0002) /* Bitplane page mode */
+#define FMODE_BPL32	(0x0001) /* Bitplane 32 bit fetch */
 
+	/*
+	 * Tags used to indicate a specific Pixel Clock
+	 *
+	 * clk_shift is the shift value to get the timings in 35 ns units
+	 */
 
-   /*
-    *    Chip RAM we reserve for the Frame Buffer (must be a multiple of 4K!)
-    *
-    *    This defines the Maximum Virtual Screen Size
-    */
+enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
 
-#define VIDEOMEMSIZE_AGA_2M   (1310720)   /* AGA (2MB) : max 1280*1024*256 */
-#define VIDEOMEMSIZE_AGA_1M    (393216)   /* AGA (1MB) : max 1024*768*256 */
-#define VIDEOMEMSIZE_ECS_2M    (655360)   /* ECS (2MB) : max 1280*1024*16 */
-#define VIDEOMEMSIZE_ECS_1M    (393216)   /* ECS (1MB) : max 1024*768*16 */
-#define VIDEOMEMSIZE_OCS       (262144)   /* OCS       : max ca. 800*600*16 */
+	/*
+	 * Tags used to indicate the specific chipset
+	 */
 
+enum { TAG_OCS, TAG_ECS, TAG_AGA };
 
-static u_long videomemory;
-static u_long videomemorysize;
+	/*
+	 * Tags used to indicate the memory bandwidth
+	 */
 
-#define assignchunk(name, type, ptr, size) \
-{ \
-   (name) = (type)(ptr); \
-   ptr += size; \
-}
+enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
 
 
-   /*
-    *    Copper Instructions
-    */
+	/*
+	 * Clock Definitions, Maximum Display Depth
+	 *
+	 * These depend on the E-Clock or the Chipset, so they are filled in
+	 * dynamically
+	 */
 
-#define CMOVE(val, reg)       (CUSTOM_OFS(reg)<<16 | (val))
-#define CMOVE2(val, reg)      ((CUSTOM_OFS(reg)+2)<<16 | (val))
-#define CWAIT(x, y)           (((y) & 0xff)<<24 | ((x) & 0xfe)<<16 | 0x0001fffe)
-#define CEND                  (0xfffffffe)
+static u_long pixclock[3];	/* SHRES/HIRES/LORES: index = clk_shift */
+static u_short maxdepth[3];	/* SHRES/HIRES/LORES: index = clk_shift */
+static u_short maxfmode, chipset;
 
 
-typedef union {
-   u_long l;
-   u_short w[2];
-} copins;
+	/*
+	 * Broadcast Video Timings
+	 *
+	 * Horizontal values are in 35 ns (SHRES) units
+	 * Vertical values are in interlaced scanlines
+	 */
 
+#define PAL_DIWSTRT_H	(360)	/* PAL Window Limits */
+#define PAL_DIWSTRT_V	(48)
+#define PAL_HTOTAL	(1816)
+#define PAL_VTOTAL	(625)
+
+#define NTSC_DIWSTRT_H	(360)	/* NTSC Window Limits */
+#define NTSC_DIWSTRT_V	(40)
+#define NTSC_HTOTAL	(1816)
+#define NTSC_VTOTAL	(525)
 
-   /*
-    *    Frame Header Copper List
-    */
-
-struct clist_hdr {
-   copins bplcon0;
-   copins diwstrt;
-   copins diwstop;
-   copins diwhigh;
-   copins sprfix[8];
-   copins sprstrtup[16];
-   copins wait;
-   copins jump;
-   copins wait_forever;
-};
 
+	/*
+	 * Monitor Specifications
+	 *
+	 * These are typical for a `generic' Amiga monitor (e.g. A1960)
+	 */
 
-   /*
-    *    Long Frame/Short Frame Copper List
-    */
-
-struct clist_dyn {
-   copins diwstrt;
-   copins diwstop;
-   copins diwhigh;
-   copins bplcon0;
-   copins sprpt[2];              /* Sprite 0 */
-   copins rest[64];
-};
+static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
 
 
-static struct clist_hdr *clist_hdr;
-static struct clist_dyn *clist_lof;
-static struct clist_dyn *clist_shf;    /* Only used for Interlace */
+	/*
+	 * Various macros
+	 */
 
+#define up2(v)		(((v)+1) & -2)
+#define down2(v)	((v) & -2)
+#define div2(v)		((v)>>1)
+#define mod2(v)		((v) & 1)
+
+#define up4(v)		(((v)+3) & -4)
+#define down4(v)	((v) & -4)
+#define mul4(v)		((v)<<2)
+#define div4(v)		((v)>>2)
+#define mod4(v)		((v) & 3)
+
+#define up8(v)		(((v)+7) & -8)
+#define down8(v)	((v) & -8)
+#define div8(v)		((v)>>3)
+#define mod8(v)		((v) & 7)
+
+#define up16(v)		(((v)+15) & -16)
+#define down16(v)	((v) & -16)
+#define div16(v)	((v)>>4)
+#define mod16(v)	((v) & 15)
+
+#define up32(v)		(((v)+31) & -32)
+#define down32(v)	((v) & -32)
+#define div32(v)	((v)>>5)
+#define mod32(v)	((v) & 31)
+
+#define up64(v)		(((v)+63) & -64)
+#define down64(v)	((v) & -64)
+#define div64(v)	((v)>>6)
+#define mod64(v)	((v) & 63)
+
+#define upx(x,v)	(((v)+(x)-1) & -(x))
+#define downx(x,v)	((v) & -(x))
+#define modx(x,v)	((v) & ((x)-1))
+
+/* if x1 is not a constant, this macro won't make real sense :-) */
+#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
+	"d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
+
+#define min(a, b)	((a) < (b) ? (a) : (b))
+#define max(a, b)	((a) > (b) ? (a) : (b))
 
-   /*
-    *    Hardware Cursor
-    */
+#define highw(x)	((u_long)(x)>>16 & 0xffff)
+#define loww(x)		((u_long)(x) & 0xffff)
 
-#define CRSR_RATE       (20)     /* Number of frames/flash toggle */
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
 
-static u_long *lofsprite, *shfsprite, *dummysprite;
-static u_short cursormode = FB_CURSOR_FLASH;
+#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPER
+#define VBlankOff()	custom.intena = IF_COPER
 
 
-   /*
-    *    Current Video Mode
-    */
+	/*
+	 * Chip RAM we reserve for the Frame Buffer
+	 *
+	 * This defines the Maximum Virtual Screen Size
+	 * (Setable per kernel options?)
+	 */
 
-struct amiga_fb_par {
+#define VIDEOMEMSIZE_AGA_2M	(1310720) /* AGA (2MB) : max 1280*1024*256  */
+#define VIDEOMEMSIZE_AGA_1M	(786432)  /* AGA (1MB) : max 1024*768*256   */
+#define VIDEOMEMSIZE_ECS_2M	(655360)  /* ECS (2MB) : max 1280*1024*16   */
+#define VIDEOMEMSIZE_ECS_1M	(393216)  /* ECS (1MB) : max 1024*768*16    */
+#define VIDEOMEMSIZE_OCS	(262144)  /* OCS       : max ca. 800*600*16 */
 
-   /* General Values */
+#define SPRITEMEMSIZE		(64*64/4) /* max 64*64*4 */
+#define DUMMYSPRITEMEMSIZE	(8)
 
-   int xres;                     /* vmode */
-   int yres;                     /* vmode */
-   int vxres;                    /* vmode */
-   int vyres;                    /* vmode */
-   int xoffset;                  /* vmode */
-   int yoffset;                  /* vmode */
-   u_short bpp;                  /* vmode */
-   u_short clk_shift;            /* vmode */
-   int vmode;                    /* vmode */
-   u_short diwstrt_h;            /* vmode */
-   u_short diwstrt_v;            /* vmode */
-   u_long next_line;             /* modulo for next line */
-   u_long next_plane;            /* modulo for next plane */
-   short crsr_x;                 /* movecursor */
-   short crsr_y;                 /* movecursor */
-
-   /* OCS Hardware Registers */
-
-   u_long bplpt0;                /* vmode, pan (Note: physical address) */
-   u_short bplcon0;              /* vmode */
-   u_short bplcon1;              /* vmode, pan */
-   u_short bpl1mod;              /* vmode, pan */
-   u_short bpl2mod;              /* vmode, pan */
-   u_short diwstrt;              /* vmode */
-   u_short diwstop;              /* vmode */
-   u_short ddfstrt;              /* vmode, pan */
-   u_short ddfstop;              /* vmode, pan */
-
-#if defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
-   /* Additional ECS Hardware Registers */
-
-   u_short diwhigh;              /* vmode */
-   u_short bplcon3;              /* vmode */
-   u_short beamcon0;             /* vmode */
-   u_short htotal;               /* vmode */
-   u_short hsstrt;               /* vmode */
-   u_short hsstop;               /* vmode */
-   u_short vtotal;               /* vmode */
-   u_short vsstrt;               /* vmode */
-   u_short vsstop;               /* vmode */
-   u_short hcenter;              /* vmode */
-#endif /* defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA) */
+static u_long videomemory, spritememory;
+static u_long videomemorysize;
 
-#if defined(CONFIG_AMIFB_AGA)
-   /* Additional AGA Hardware Registers */
+	/*
+	 * This is the earliest allowed start of fetching display data.
+	 * Only if you really want no hardware cursor and audio,
+	 * set this to 128, but let it better at 192
+	 */
 
-   u_short fmode;                /* vmode */
-#endif /* defined(CONFIG_AMIFB_AGA) */
-};
+static u_long min_fstrt = 192;
 
-static struct amiga_fb_par current_par;
+#define assignchunk(name, type, ptr, size) \
+{ \
+	(name) = (type)(ptr); \
+	ptr += size; \
+}
 
-static int current_par_valid = 0;
-static int currcon = 0;
 
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
+	/*
+	 * Copper Instructions
+	 */
 
-static int node;        /* node of the /dev/fb?current file */
+#define CMOVE(val, reg)		(CUSTOM_OFS(reg)<<16 | (val))
+#define CMOVE2(val, reg)	((CUSTOM_OFS(reg)+2)<<16 | (val))
+#define CWAIT(x, y)		(((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
+#define CEND			(0xfffffffe)
 
 
-   /*
-    *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-    *    (Imported from arch/m68k/amiga/amisound.c)
-    */
+typedef union {
+	u_long l;
+	u_short w[2];
+} copins;
 
-extern volatile u_short amiga_audio_min_period;
+struct copdisplay {
+	copins *init;
+	copins *wait;
+	copins *list[2][2];
+	copins *rebuild[2];
+} copdisplay;
 
+static u_short currentcop = 0;
 
-   /*
-    *    Since we can't read the palette on OCS/ECS, and since reading one
-    *    single color palette entry requires 5 expensive custom chip bus
-    *    accesses on AGA, we keep a copy of the current palette.
-    */
+	/*
+	 * Hardware Cursor
+	 */
 
-#ifdef CONFIG_AMIFB_AGA
-static struct { u_char red, green, blue, pad; } palette[256];
-#else /* CONFIG_AMIFB_AGA */
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif /* CONFIG_AMIFB_AGA */
+static int cursorrate = 20;	/* Number of frames/flash toggle */
+static u_short cursorstate = -1;
+static u_short cursormode = FB_CURSOR_OFF;
 
+static u_short *lofsprite, *shfsprite, *dummysprite;
 
-   /*
-    *    Latches and Flags for display changes during VBlank
-    */
-
-static volatile u_short do_vmode = 0;           /* Change the Video Mode */
-static volatile short do_blank = 0;             /* (Un)Blank the Screen (±1) */
-static volatile u_short do_movecursor = 0;      /* Move the Cursor */
-static volatile u_short full_vmode_change = 1;  /* Full Change or Only Pan */
-static volatile u_short is_blanked = 0;         /* Screen is Blanked */
-
-
-   /*
-    *    Switch for Chipset Independency
-    */
-
-static struct fb_hwswitch {
-
-   /* Initialization */
-   int (*init)(void);
-
-   /* Display Control */
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct amiga_fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
-   int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
-                    u_int *transp);
-   int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
-                    u_int transp);
-   int (*pan_display)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
-
-   /* Routines Called by VBlank Interrupt to minimize flicker */
-   void (*do_vmode)(void);
-   void (*do_blank)(int blank);
-   void (*do_movecursor)(void);
-   void (*do_flashcursor)(void);
-} *fbhw;
-
-
-   /*
-    *    Frame Buffer Name
-    *
-    *    The rest of the name is filled in by amiga_fb_init
-    */
+	/*
+	 * Current Video Mode
+	 */
 
-static char amiga_fb_name[16] = "Amiga ";
+struct amiga_fb_par {
 
+	/* General Values */
 
-   /*
-    *    Predefined Video Mode Names
-    *
-    *    The a2024-?? modes don't work yet because there's no A2024 driver.
-    */
+	int xres;		/* vmode */
+	int yres;		/* vmode */
+	int vxres;		/* vmode */
+	int vyres;		/* vmode */
+	int xoffset;		/* vmode */
+	int yoffset;		/* vmode */
+	u_short bpp;		/* vmode */
+	u_short clk_shift;	/* vmode */
+	u_short line_shift;	/* vmode */
+	int vmode;		/* vmode */
+	u_short diwstrt_h;	/* vmode */
+	u_short diwstop_h;	/* vmode */
+	u_short diwstrt_v;	/* vmode */
+	u_short diwstop_v;	/* vmode */
+	u_long next_line;	/* modulo for next line */
+	u_long next_plane;	/* modulo for next plane */
+
+	/* Cursor Values */
+
+	struct {
+		short crsr_x;	/* movecursor */
+		short crsr_y;	/* movecursor */
+		short spot_x;
+		short spot_y;
+		u_short height;
+		u_short width;
+		u_short fmode;
+	} crsr;
+
+	/* OCS Hardware Registers */
+
+	u_long bplpt0;		/* vmode, pan (Note: physical address) */
+	u_long bplpt0wrap;	/* vmode, pan (Note: physical address) */
+	u_short ddfstrt;
+	u_short ddfstop;
+	u_short bpl1mod;
+	u_short bpl2mod;
+	u_short bplcon0;	/* vmode */
+	u_short bplcon1;	/* vmode */
+	u_short htotal;		/* vmode */
+	u_short vtotal;		/* vmode */
+
+	/* Additional ECS Hardware Registers */
+
+	u_short bplcon3;	/* vmode */
+	u_short beamcon0;	/* vmode */
+	u_short hsstrt;		/* vmode */
+	u_short hsstop;		/* vmode */
+	u_short hbstrt;		/* vmode */
+	u_short hbstop;		/* vmode */
+	u_short vsstrt;		/* vmode */
+	u_short vsstop;		/* vmode */
+	u_short vbstrt;		/* vmode */
+	u_short vbstop;		/* vmode */
+	u_short hcenter;	/* vmode */
 
-static char *amiga_fb_modenames[] = {
+	/* Additional AGA Hardware Registers */
 
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   "default",
-
-   /*
-    *    AmigaOS Video Modes
-    */
-    
-   "ntsc",              /* 640x200, 15 kHz, 60 Hz (NTSC) */
-   "ntsc-lace",         /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
-   "pal",               /* 640x256, 15 kHz, 50 Hz (PAL) */
-   "pal-lace",          /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
-   "multiscan",         /* 640x480, 29 kHz, 57 Hz */
-   "multiscan-lace",    /* 640x960, 29 kHz, 57 Hz interlaced */
-   "a2024-10",          /* 1024x800, 10 Hz (Not yet supported) */
-   "a2024-15",          /* 1024x800, 15 Hz (Not yet supported) */
-   "euro36",            /* 640x200, 15 kHz, 72 Hz */
-   "euro36-lace",       /* 640x400, 15 kHz, 72 Hz interlaced */
-   "euro72",            /* 640x400, 29 kHz, 68 Hz */
-   "euro72-lace",       /* 640x800, 29 kHz, 68 Hz interlaced */
-   "super72",           /* 800x300, 23 kHz, 70 Hz */
-   "super72-lace",      /* 800x600, 23 kHz, 70 Hz interlaced */
-   "dblntsc",           /* 640x200, 27 kHz, 57 Hz doublescan */
-   "dblntsc-ff",        /* 640x400, 27 kHz, 57 Hz */
-   "dblntsc-lace",      /* 640x800, 27 kHz, 57 Hz interlaced */
-   "dblpal",            /* 640x256, 27 kHz, 47 Hz doublescan */
-   "dblpal-ff",         /* 640x512, 27 kHz, 47 Hz */
-   "dblpal-lace",       /* 640x1024, 27 kHz, 47 Hz interlaced */
-
-   /*
-    *    VGA Video Modes
-    */
-
-   "vga",               /* 640x480, 31 kHz, 60 Hz (VGA) */
-   "vga70",             /* 640x400, 31 kHz, 70 Hz (VGA) */
-
-   /*
-    *    User Defined Video Modes: to be set after boot up using e.g. fbset
-    */
+	u_short fmode;		/* vmode */
+} currentpar;
 
-   "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
+static int currcon = 0;
 
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
 
-   /*
-    *    Predefined Video Mode Definitions
-    *
-    *    Since the actual pixclock values depend on the E-Clock, we use the
-    *    TAG_* values and fill in the real values during initialization.
-    *    Thus we assume no one has pixel clocks of 333, 500 or 1000 GHz :-)
-    */
-
-static struct fb_var_screeninfo amiga_fb_predefined[] = {
-
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   { 0, },
-
-   /*
-    *    AmigaOS Video Modes
-    */
-    
-   {
-      /* ntsc */
-      640, 200, 640, 200, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 24, 18, 0, 0,
-      FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
-   }, {
-      /* ntsc-lace */
-      640, 400, 640, 400, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 48, 36, 0, 0,
-      FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
-   }, {
-      /* pal */
-      640, 256, 640, 256, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 20, 12, 0, 0,
-      FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
-   }, {
-      /* pal-lace */
-      640, 512, 640, 512, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 40, 24, 0, 0,
-      FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
-   }, {
-      /* multiscan */
-      640, 480, 640, 480, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* multiscan-lace */
-      640, 960, 640, 960, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
-      0, FB_VMODE_INTERLACED
-   }, {
-      /* a2024-10 (Not yet supported) */
-      1024, 800, 1024, 800, 0, 0, 2, 0,
-      {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* a2024-15 (Not yet supported) */
-      1024, 800, 1024, 800, 0, 0, 2, 0,
-      {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* euro36 */
-      640, 200, 640, 200, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* euro36-lace */
-      640, 400, 640, 400, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
-      0, FB_VMODE_INTERLACED
-   }, {
-      /* euro72 */
-      640, 400, 640, 400, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* euro72-lace */
-      640, 800, 640, 800, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
-      0, FB_VMODE_INTERLACED
-   }, {
-      /* super72 */
-      800, 300, 800, 300, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* super72-lace */
-      800, 600, 800, 600, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
-      0, FB_VMODE_INTERLACED
-   }, {
-      /* dblntsc */
-      640, 200, 640, 200, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
-      0, FB_VMODE_DOUBLE
-   }, {
-      /* dblntsc-ff */
-      640, 400, 640, 400, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* dblntsc-lace */
-      640, 800, 640, 800, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
-      0, FB_VMODE_INTERLACED
-   }, {
-      /* dblpal */
-      640, 256, 640, 256, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
-      0, FB_VMODE_DOUBLE
-   }, {
-      /* dblpal-ff */
-      640, 512, 640, 512, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* dblpal-lace */
-      640, 1024, 640, 1024, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
-      0, FB_VMODE_INTERLACED
-   },
-
-   /*
-    *    VGA Video Modes
-    */
-
-   {
-      /* vga */
-      640, 480, 640, 480, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
-      0, FB_VMODE_NONINTERLACED
-   }, {
-      /* vga70 */
-      640, 400, 640, 400, 0, 0, 4, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
-      FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-
-   /*
-    *    User Defined Video Modes
-    */
+static int node;		/* node of the /dev/fb?current file */
 
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
+	/*
+	 * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+	 * (Imported from arch/m68k/amiga/amisound.c)
+	 */
 
+extern volatile u_short amiga_audio_min_period;
 
-#define NUM_USER_MODES     (8)
-#define NUM_TOTAL_MODES    arraysize(amiga_fb_predefined)
-#define NUM_PREDEF_MODES   (NUM_TOTAL_MODES-NUM_USER_MODES)
+	/*
+	 * Since we can't read the palette on OCS/ECS, and since reading one
+	 * single color palette entry require 5 expensive custom chip bus accesses
+	 * on AGA, we keep a copy of the current palette.
+	 */
 
+#if defined(CONFIG_AMIFB_AGA)
+static struct { u_char red, green, blue, pad; } palette[256];
+#else
+static struct { u_char red, green, blue, pad; } palette[32];
+#endif
 
-static int amifb_ilbm = 0;       /* interleaved or normal bitplanes */
+#if defined(CONFIG_AMIFB_ECS)
+static u_short ecs_palette[32];
+#endif
 
-static int amifb_inverse = 0;
-static int amifb_mode = 0;
+	/*
+	 * Latches for Display Changes during VBlank
+	 */
 
+static u_short do_vmode_full = 0;	/* Change the Video Mode */
+static u_short do_vmode_pan = 0;	/* Update the Video Mode */
+static short do_blank = 0;		/* (Un)Blank the Screen (±1) */
+static u_short do_cursor = 0;		/* Move the Cursor */
 
-   /*
-    *    Support for Graphics Boards
-    */
 
-#ifdef CONFIG_FB_CYBER        /* Cybervision */
-extern int Cyber_probe(void);
-extern void Cyber_video_setup(char *options, int *ints);
-extern struct fb_info *Cyber_fb_init(long *mem_start);
+	/*
+	 * Various Flags
+	 */
 
-static int amifb_Cyber = 0;
-#endif /* CONFIG_FB_CYBER */
+static u_short is_blanked = 0;		/* Screen is Blanked */
+static u_short is_lace = 0;		/* Screen is laced */
 
+	/*
+	 * Frame Buffer Name
+	 *
+	 * The rest of the name is filled in during initialization
+	 */
 
-   /*
-    *    Some default modes
-    */
-
-#define DEFMODE_PAL        "pal"       /* for PAL OCS/ECS */
-#define DEFMODE_NTSC       "ntsc"      /* for NTSC OCS/ECS */
-#define DEFMODE_AMBER_PAL  "pal-lace"  /* for flicker fixed PAL (A3000) */
-#define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */
-#define DEFMODE_AGA        "vga70"     /* for AGA */
+static char amiga_fb_name[16] = "Amiga ";
 
+	/*
+	 * Predefined Video Mode Names
+	 *
+	 * The a2024-?? modes don't work yet because there's no A2024 driver.
+	 */
 
-   /*
-    *    Interface used by the world
-    */
+static char *amiga_fb_modenames[] = {
 
-void amiga_video_setup(char *options, int *ints);
+	/*
+	 * Autodetect (Default) Video Mode
+	 */
 
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
+	"default",
 
-static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                          u_long arg, int con);
+	/*
+	 * AmigaOS Video Modes
+	 */
 
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
+	"ntsc",			/* 640x200, 15 kHz, 60 Hz (NTSC) */
+	"ntsc-lace",		/* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
+	"pal",			/* 640x256, 15 kHz, 50 Hz (PAL) */
+	"pal-lace",		/* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
+	"multiscan",		/* 640x480, 29 kHz, 57 Hz */
+	"multiscan-lace",	/* 640x960, 29 kHz, 57 Hz interlaced */
+	"a2024-10",		/* 1024x800, 10 Hz (Not yet supported) */
+	"a2024-15",		/* 1024x800, 15 Hz (Not yet supported) */
+	"euro36",		/* 640x200, 15 kHz, 72 Hz */
+	"euro36-lace",		/* 640x400, 15 kHz, 72 Hz interlaced */
+	"euro72",		/* 640x400, 29 kHz, 68 Hz */
+	"euro72-lace",		/* 640x800, 29 kHz, 68 Hz interlaced */
+	"super72",		/* 800x300, 23 kHz, 70 Hz */
+	"super72-lace",		/* 800x600, 23 kHz, 70 Hz interlaced */
+	"dblntsc",		/* 640x200, 27 kHz, 57 Hz doublescan */
+	"dblntsc-ff",		/* 640x400, 27 kHz, 57 Hz */
+	"dblntsc-lace",		/* 640x800, 27 kHz, 57 Hz interlaced */
+	"dblpal",		/* 640x256, 27 kHz, 47 Hz doublescan */
+	"dblpal-ff",		/* 640x512, 27 kHz, 47 Hz */
+	"dblpal-lace",		/* 640x1024, 27 kHz, 47 Hz interlaced */
 
+	/*
+	 * VGA Video Modes
+	 */
 
-   /*
-    *    Interface to the low level console driver
-    */
+	"vga",			/* 640x480, 31 kHz, 60 Hz (VGA) */
+	"vga70",		/* 640x400, 31 kHz, 70 Hz (VGA) */
 
-struct fb_info *amiga_fb_init(long *mem_start);
-static int amifb_switch(int con);
-static int amifb_updatevar(int con);
-static void amifb_blank(int blank);
+	/*
+	 * User Defined Video Modes: to be set after boot up using e.g. fbset
+	 */
 
+	"user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
+};
 
-   /*
-    *    Support for OCS
-    */
+struct fb_var_screeninfo amiga_fb_predefined[] = {
 
-#ifdef CONFIG_AMIFB_OCS
-#error "OCS support: not yet implemented"
-#endif /* CONFIG_AMIFB_OCS */
+	/*
+	 * Autodetect (Default) Video Mode
+	 */
 
+	{ 0, },
 
-   /*
-    *    Support for ECS
-    */
+	/*
+	 * AmigaOS Video Modes
+	 */
 
-#ifdef CONFIG_AMIFB_ECS
-#error "ECS support: not yet implemented"
-#endif /* CONFIG_AMIFB_ECS */
+	{
+		/* ntsc */
+		640, 200, 640, 200, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 44, 16, 76, 2,
+		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* ntsc-lace */
+		640, 400, 640, 400, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 88, 33, 76, 4,
+		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* pal */
+		640, 256, 640, 256, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 40, 14, 76, 2,
+		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* pal-lace */
+		640, 512, 640, 512, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 80, 29, 76, 4,
+		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* multiscan */
+		640, 480, 640, 480, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 29, 8, 72, 8,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
 
+	}, {
+		/* multiscan-lace */
+		640, 960, 640, 960, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 58, 16, 72, 16,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* a2024-10 (Not yet supported) */
+		1024, 800, 1024, 800, 0, 0, 2, 0,
+		{0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* a2024-15 (Not yet supported) */
+		1024, 800, 1024, 800, 0, 0, 2, 0,
+		{0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* euro36 */
+		640, 200, 640, 200, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* euro36-lace */
+		640, 400, 640, 400, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* euro72 */
+		640, 400, 640, 400, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* euro72-lace */
+		640, 800, 640, 800, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* super72 */
+		800, 300, 800, 300, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* super72-lace */
+		800, 600, 800, 600, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* dblntsc */
+		640, 200, 640, 200, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
+		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+	}, {
+		/* dblntsc-ff */
+		640, 400, 640, 400, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* dblntsc-lace */
+		640, 800, 640, 800, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* dblpal */
+		640, 256, 640, 256, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
+		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+	}, {
+		/* dblpal-ff */
+		640, 512, 640, 512, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* dblpal-lace */
+		640, 1024, 640, 1024, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
+		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+	},
 
-   /*
-    *    Support for AGA
-    */
+	/*
+	 * VGA Video Modes
+	 */
 
-#ifdef CONFIG_AMIFB_AGA
-static int aga_init(void);
-static int aga_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amiga_fb_par *par);
-static int aga_decode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par);
-static int aga_encode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par);
-static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp);
-static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp);
-static int aga_pan_display(struct fb_var_screeninfo *var,
-                           struct amiga_fb_par *par);
-static void aga_do_vmode(void);
-static void aga_do_blank(int blank);
-static void aga_do_movecursor(void);
-static void aga_do_flashcursor(void);
-
-static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
-static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
-static int aga_get_cursorstate(struct fb_cursorstate *state, int con);
-static int aga_set_cursorstate(struct fb_cursorstate *state, int con);
-
-static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop);
-static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
-                                            struct amiga_fb_par *par);
-static void aga_build_clist_dyn(struct clist_dyn *cop,
-                                struct clist_dyn *othercop, u_short shf,
-                                struct amiga_fb_par *par);
-#endif /* CONFIG_AMIFB_AGA */
+	{
+		/* vga */
+		640, 480, 640, 480, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* vga70 */
+		640, 400, 640, 400, 0, 0, 4, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
+		FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	},
 
+	/*
+	 * User Defined Video Modes
+	 */
 
-   /*
-    *    Internal routines
-    */
+	{ 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+};
 
-static u_long chipalloc(u_long size);
-static void amiga_fb_get_par(struct amiga_fb_par *par);
-static void amiga_fb_set_par(struct amiga_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 amiga_fb_set_disp(int con);
-static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy);
-static char * strtoke(char * s,const char * ct);
-static int get_video_mode(const char *name);
-static void check_default_mode(void);
+#define NUM_USER_MODES   (8)
+#define NUM_TOTAL_MODES  arraysize(amiga_fb_predefined)
+#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES)
 
+static int amifb_ilbm = 0;	/* interleaved or normal bitplanes */
 
-#ifdef USE_MONO_AMIFB_IF_NON_AGA
+static int amifb_inverse = 0;
+static int amifb_usermode = 0;
 
-/******************************************************************************
-*
-* This is the old monochrome frame buffer device. It's invoked if we're running
-* on a non-AGA machine, until the color support for OCS/ECS is finished.
-*
-******************************************************************************/
-
-/*
- * atari/atafb.c -- Low level implementation of Atari frame buffer device
- * amiga/amifb.c -- Low level implementation of Amiga frame buffer device
- *
- *  Copyright (C) 1994 Martin Schaller & Roman Hodek & 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.
- *
- * History:
- *   - 03 Jan 95: Original version my Martin Schaller: The TT driver and
- *                all the device independent stuff
- *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
- *                and wrote the Falcon, ST(E), and External drivers
- *                based on the original TT driver.
- *   - 26 Jan 95: Geert: Amiga version
- *   - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga
- *		  frame buffer device.  This provides ECS support and the
- *		  following screen-modes: multiscan, multiscan-lace,
- * 		  super72, super72-lace, dblntsc, dblpal & euro72.
- *		  He suggests that we remove the old AGA screenmodes,
- *		  as they are non-standard, and some of them doesn't work
- *		  under ECS.
- */
+	/*
+	 * Some default modes
+	 */
 
-static struct mono_mono_amiga_fb_par {
-	u_long smem_start;
-	u_long smem_len;
-	struct geometry *geometry;
-	ushort scr_max_height;			/* screen dimensions */
-	ushort scr_max_width;
-	ushort scr_height;
-	ushort scr_width;
-	ushort scr_depth;
-	int bytes_per_row;			/* offset to one line below */
-	ulong fgcol;
-	ulong bgcol;
-	ulong crsrcol;
-	ushort scroll_latch;			/* Vblank support for hardware scroll */
-	ushort y_wrap;
-	ushort cursor_latch;			/* Hardware cursor */
-	ushort *cursor, *dummy;
-	ushort cursor_flash;
-	ushort cursor_visible;
-	ushort diwstrt_v, diwstrt_h;		/* display window control */
-	ushort diwstop_v, diwstop_h;
-	ushort bplcon0;				/* display mode */
-	ushort htotal;
-	u_char *bitplane[8];			/* pointers to display bitplanes */
-	ulong plane_size;
-	ushort *coplist1hdr;			/* List 1 static  component */
-	ushort *coplist1dyn;			/* List 1 dynamic component */
-	ushort *coplist2hdr;			/* List 2 static  component */
-	ushort *coplist2dyn;			/* List 2 dynamic component */
-} mono_current_par;
-
-
-static ushort mono_cursor_data[] =
-{
-    0x2c81,0x2d00,
-    0xf000,0x0000,
-    0x0000,0x0000
-};
+#define DEFMODE_PAL        "pal"	/* for PAL OCS/ECS */
+#define DEFMODE_NTSC       "ntsc"	/* for NTSC OCS/ECS */
+#define DEFMODE_AMBER_PAL  "pal-lace"	/* for flicker fixed PAL (A3000) */
+#define DEFMODE_AMBER_NTSC "ntsc-lace"	/* for flicker fixed NTSC (A3000) */
+#define DEFMODE_AGA        "vga70"	/* for AGA */
 
+	/*
+	 * Macros for the conversion from real world values to hardware register
+	 * values
+	 *
+	 * This helps us to keep our attention on the real stuff...
+	 *
+	 * Hardware limits for AGA:
+	 *
+	 *	parameter  min    max  step
+	 *	---------  ---   ----  ----
+	 *	diwstrt_h    0   2047     1
+	 *	diwstrt_v    0   2047     1
+	 *	diwstop_h    0   4095     1
+	 *	diwstop_v    0   4095     1
+	 *
+	 *	ddfstrt      0   2032    16
+	 *	ddfstop      0   2032    16
+	 *
+	 *	htotal       8   2048     8
+	 *	hsstrt       0   2040     8
+	 *	hsstop       0   2040     8
+	 *	vtotal       1   4096     1
+	 *	vsstrt       0   4095     1
+	 *	vsstop       0   4095     1
+	 *	hcenter      0   2040     8
+	 *
+	 *	hbstrt       0   2047     1
+	 *	hbstop       0   2047     1
+	 *	vbstrt       0   4095     1
+	 *	vbstop       0   4095     1
+	 *
+	 * Horizontal values are in 35 ns (SHRES) pixels
+	 * Vertical values are in half scanlines
+	 */
 
-/*
- *  Color definitions
- */
+/* bplcon1 (smooth scrolling) */
 
-#define FG_COLOR		(0x000000)	/* black */
-#define BG_COLOR		(0xaaaaaa)	/* lt. grey */
-#define CRSR_COLOR		(0xff0000)	/* bright red */
-
-#define FG_COLOR_INV		BG_COLOR
-#define BG_COLOR_INV		FG_COLOR
-#define CRSR_COLOR_INV		(0x6677aa)	/* a blue-ish color */
+#define hscroll2hw(hscroll) \
+	(((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
+	 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
 
-/*
- *  Split 24-bit RGB colors in 12-bit MSB (for OCS/ECS/AGA) and LSB (for AGA)
- */
+/* diwstrt/diwstop/diwhigh (visible display window) */
 
-#define COLOR_MSB(rgb)	(((rgb>>12)&0xf00)|((rgb>>8)&0x0f0)|((rgb>>4)&0x00f))
-#define COLOR_LSB(rgb)	(((rgb>>8) &0xf00)|((rgb>>4)&0x0f0)|((rgb)   &0x00f))
+#define diwstrt2hw(diwstrt_h, diwstrt_v) \
+	(((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
+#define diwstop2hw(diwstop_h, diwstop_v) \
+	(((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
+#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
+	(((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
+	 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
+	 ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
 
-/* Cursor definitions */
+/* ddfstrt/ddfstop (display DMA) */
 
-#define CRSR_FLASH		1	/* Cursor flashing on(1)/off(0) */
-#define CRSR_BLOCK		1	/* Block(1) or line(0) cursor */
+#define ddfstrt2hw(ddfstrt)	div8(ddfstrt)
+#define ddfstop2hw(ddfstop)	div8(ddfstop)
 
+/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
 
-/* controlling screen blanking (read in VBL handler) */
-static int mono_do_blank;
-static int mono_do_unblank;
-static unsigned short mono_save_bplcon3;
+#define hsstrt2hw(hsstrt)	(div8(hsstrt))
+#define hsstop2hw(hsstop)	(div8(hsstop))
+#define htotal2hw(htotal)	(div8(htotal)-1)
+#define vsstrt2hw(vsstrt)	(div2(vsstrt))
+#define vsstop2hw(vsstop)	(div2(vsstop))
+#define vtotal2hw(vtotal)	(div2(vtotal)-1)
+#define hcenter2hw(htotal)	(div8(htotal))
 
-/*
- * mono_ecs_color_zero is used to keep custom.color[0] for the special ECS color-
- * table, as custom.color[0] is cleared at vblank interrupts.
- * -Jes (jds@kom.auc.dk)
- */
+/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
 
-static ushort mono_ecs_color_zero;
+#define hbstrt2hw(hbstrt)	(((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
+#define hbstop2hw(hbstop)	(((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
+#define vbstrt2hw(vbstrt)	(div2(vbstrt))
+#define vbstop2hw(vbstop)	(div2(vbstop))
+
+/* colour */
+
+#define rgb2hw8_high(red, green, blue) \
+	(((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
+#define rgb2hw8_low(red, green, blue) \
+	(((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
+#define rgb2hw4(red, green, blue) \
+	(((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
+#define rgb2hw2(red, green, blue) \
+	(((red)<<10 & 0xc00) | ((green)<<6 & 0x0c0) | ((blue)<<2 & 0x00c))
 
-static struct {
-	int right_count;
-	int done;
-} mono_vblank;
+/* sprpos/sprctl (sprite positioning) */
 
+#define spr2hw_pos(start_v, start_h) \
+	(((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
+#define spr2hw_ctl(start_v, start_h, stop_v) \
+	(((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
+	 ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
+	 ((start_h)>>2&0x0001))
 
-static __inline__ void mono_init_vblank(void)
-{
-	mono_vblank.right_count = 0;
-	mono_vblank.done = 0;
-}
+/* get current vertical position of beam */
+#define get_vbpos()	((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
 
-/* Geometry structure contains all useful information about given mode.
- *
- * Strictly speaking `scr_max_height' and `scr_max_width' is redundant
- * information with DIWSTRT value provided. Might be useful if modes
- * can be hotwired by user in future. It fits for the moment.
- *
- * At the moment, the code only distinguishes between OCS and AGA. ECS
- * lies somewhere in between - someone more familiar with it could make
- * appropriate modifications so that some advanced display modes are
- * available, without confusing the poor chipset. OCS modes use only the
- * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could
- * be used as well). -wjr
- *
- * The code now supports ECS as well, except for FMODE all control registers
- * are the same under ECS. A special color-table has to be generated though.
- * -Jes
- */
-struct geometry {
-    char *modename;	/* Name this thing */
-    char isOCS;		/* Is it OCS or ECS/AGA */
-    ushort bplcon0;	/* Values for bit plane control register 0 */
-    ushort scr_width;
-    ushort scr_height;
-    ushort scr_depth;
-    ushort scr_max_width;     /* Historical, might be useful still */
-    ushort scr_max_height;
-    ushort diwstrt_h;	/* Where the display window starts */
-    ushort diwstrt_v;
-    ushort alignment;	/* Pixels per scanline must be a multiple of this */
-    /* OCS doesn't need anything past here */
-    ushort bplcon2;
-    ushort bplcon3;
-    /* The rest of these control variable sync */
-    ushort htotal;	/* Total hclocks */
-    ushort hsstrt;	/* HSYNC start and stop */
-    ushort hsstop;
-    ushort hbstrt;	/* HBLANK start and stop */
-    ushort hbstop;
-    ushort vtotal;	/* Total vlines */
-    ushort vsstrt;	/* VSYNC, VBLANK ditto */
-    ushort vsstop;
-    ushort vbstrt;
-    ushort vbstop;
-    ushort hcenter;	/* Center of line, for interlaced modes */
-    ushort beamcon0;	/* Beam control */
-    ushort fmode;	/* Memory fetch mode */
-};
+	/*
+	 * Copper Initialisation List
+	 */
 
-#define MAX_COP_LIST_ENTS 64
-#define COP_MEM_REQ       (MAX_COP_LIST_ENTS*4*2)
-#define SPR_MEM_REQ       (24)
+#define COPINITSIZE (sizeof(copins)*40)
 
+enum {
+	cip_bplcon0
+};
 
-static struct geometry mono_modes[] = {
-	/* NTSC modes: !!! can't guarantee anything about overscan modes !!! */
-	{
-		"ntsc-lace", 1,
-		BPC0_HIRES | BPC0_LACE,
-		640, 400, 1,
-		704, 480,
-		0x71, 0x18,		/* diwstrt h,v */
-		16			/* WORD aligned */
-	}, {
-		"ntsc", 1,
-		BPC0_HIRES,
-		640, 200, 1,
-		704, 240,
-		0x71, 0x18,
-		16			/* WORD aligned */
-	}, {
-		"ntsc-lace-over", 1,
-		BPC0_HIRES | BPC0_LACE,
-		704, 480, 1,
-		704, 480,
-		0x71, 0x18,
-		16			/* WORD aligned */
-	}, {
-		"ntsc-over", 1,
-		BPC0_HIRES,
-		704, 240, 1,
-		704, 240,
-		0x71, 0x18,
-		16			/* WORD aligned */
-	},
-	/* PAL modes. Warning:
-	 * 
-	 * PAL overscan causes problems on my machine because maximum diwstop_h
-	 * value seems to be ~0x1c2, rather than 0x1e0+ inferred by RKM 1.1
-	 * and 0x1d5 inferred by original `amicon.c' source. Is this a hardware
-	 * limitation of OCS/pal or 1084?. Or am I doing something stupid here?
-	 *
-	 * Included a couple of overscan modes that DO work on my machine,
-	 * although not particularly useful.
+	/*
+	 * Long Frame/Short Frame Copper List
+	 * Don't change the order, build_copper()/rebuild_copper() rely on this
 	 */
-	{
-		"pal-lace", 1,
-		BPC0_HIRES | BPC0_LACE,
-		640, 512, 1,
-		704, 592,
-		0x71, 0x18,
-		16			/* WORD aligned */
-	}, {
-		"pal", 1,
-		BPC0_HIRES,
-		640, 256, 1,
-		704, 296,
-		0x71, 0x18,
-		16			/* WORD aligned */
-	}, {
-		"pal-lace-over", 1,
-		BPC0_HIRES | BPC0_LACE,
-		704, 592, 1,
-		704, 582,
-		0x5b, 0x18,
-		16			/* WORD aligned */
-	}, {
-		"pal-over", 1,
-		BPC0_HIRES,
-		704, 296, 1,
-		704, 296,
-		0x5b, 0x18,
-		16			/* WORD aligned */
-
-	},
-	/* ECS modes, these are real ECS modes */
-	{
-		"multiscan", 0,
-		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
-		640, 480, 1,
-		640, 480,
-		0x0041, 0x002c,			/* diwstrt h,v */
-		64,	        		/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-
-		0x0072,				/* htotal */
-		0x000a,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0002,				/* hbstrt */
-		0x001c,				/* hbstop */
-		0x020c,				/* vtotal */
-		0x0008,				/* vsstrt */
-		0x0011,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x001c,				/* vbstop */
-		0x0043,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	{
-		"multiscan-lace", 0,
-		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
-		640, 960, 1,
-		640, 960,
-		0x0041, 0x002c,			/* diwstrt h,v */
-		64,	        		/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-
-		0x0072,				/* htotal */
-		0x000a,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0002,				/* hbstrt */
-		0x001c,				/* hbstop */
-		0x020c,				/* vtotal */
-		0x0008,				/* vsstrt */
-		0x0011,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x001c,				/* vbstop */
-		0x0043,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* Super 72 - 800x300 72Hz noninterlaced mode. */
-	{
-		"super72", 0,
-		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
-		800, 304, 1,			/* need rows%8 == 0 */
-		800, 304,			/* (cols too) */
-		0x0051, 0x0021,			/* diwstrt h,v */
-		64,				/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x0091,				/* htotal */
-		0x000a,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0001,				/* hbstrt */
-		0x001e,				/* hbstop */
-		0x0156,				/* vtotal */
-		0x0009,				/* vsstrt */
-		0x0012,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x001c,				/* vbstop */
-		0x0052,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* Super 72 lace - 800x600 72Hz interlaced mode. */
-	{
-		"super72-lace", 0,
-		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
-		800, 600, 1,			/* need rows%8 == 0 */
-		800, 600,			/* (cols too) */
-		0x0051, 0x0021,			/* diwstrt h,v */
-		64,     			/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
-						/* bplcon3 */
-		0x0091,				/* htotal */
-		0x000a,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0001,				/* hbstrt */
-		0x001e,				/* hbstop */
-		0x0150,				/* vtotal */
-		0x0009,				/* vsstrt */
-		0x0012,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x001c,				/* vbstop */
-		0x0052,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* DblNtsc - 640x400 59Hz noninterlaced mode. */
-	{
-		"dblntsc", 0,
-		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
-		640, 400, 1,			/* need rows%8 == 0 */
-		640, 400,			/* (cols too) */
-		0x0049, 0x0021,			/* diwstrt h,v */
-		64,				/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
-						/* bplcon3 */
-		0x0079,				/* htotal */
-		0x0007,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0001,				/* hbstrt */
-		0x001e,				/* hbstop */
-		0x01ec,				/* vtotal */
-		0x0008,				/* vsstrt */
-		0x0010,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x0019,				/* vbstop */
-		0x0046,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* DblPal - 640x512 52Hz noninterlaced mode. */
-	{
-		"dblpal", 0,
-		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
-		640, 512, 1,			/* need rows%8 == 0 */
-		640, 512,			/* (cols too) */
-		0x0049, 0x0021,			/* diwstrt h,v */
-		64,				/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
-						/* bplcon3 */
-		0x0079,				/* htotal */
-		0x0007,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0001,				/* hbstrt */
-		0x001e,				/* hbstop */
-		0x0234,				/* vtotal */
-		0x0008,				/* vsstrt */
-		0x0010,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x0019,				/* vbstop */
-		0x0046,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* Euro72 - productivity - 640x400 71Hz noninterlaced mode. */
-	{
-		"euro72", 0,
-		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
-		640, 400, 1,			/* need rows%8 == 0 */
-		640, 400,			/* (cols too) */
-		0x0041, 0x0021,			/* diwstrt h,v */
-		64,				/* 64-bit aligned */
-		BPC2_KILLEHB,			/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
-						/* bplcon3 */
-		0x0071,				/* htotal */
-		0x0009,				/* hsstrt */
-		0x0013,				/* hsstop */
-		0x0001,				/* hbstrt */
-		0x001e,				/* hbstop */
-		0x01be,				/* vtotal */
-		0x0008,				/* vsstrt */
-		0x0016,				/* vsstop */
-		0x0000,				/* vbstrt */
-		0x001f,				/* vbstop */
-		0x0041,				/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
-						/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
-	},
-	/* AGA modes */
-	{
-	/*
-	 * A 640x480, 60Hz noninterlaced AGA mode. It would be nice to be
-	 * able to have some of these values computed dynamically, but that
-	 * requires more knowledge of AGA than I have. At the moment,
-	 * the values make it centered on my 1960 monitor. -wjr
-	 *
-	 * For random reasons to do with the way arguments are parsed,
-	 * these names can't start with a digit.
-	 *
-	 * Don't count on being able to reduce scr_width and scr_height
-	 * and ending up with a smaller but well-formed screen - this
-	 * doesn't seem to work well at the moment.
-	 */
-		"aga640x480", 0,
-		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
-		640, 480, 1,
-		640, 480,
-		0x0041, 0x002b,						/* diwstrt h,v */
-		64,										/* 64-bit aligned */
-		BPC2_KILLEHB,							/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x0071,									/* htotal */
-		0x000c,									/* hsstrt */
-		0x001c,									/* hsstop */
-		0x0008,									/* hbstrt */
-		0x001e,									/* hbstop */
-		0x020c,									/* vtotal */
-		0x0001,									/* vsstrt */
-		0x0003,									/* vsstop */
-		0x0000,									/* vbstrt */
-		0x000f,									/* vbstop */
-		0x0046,									/* hcenter */
-		BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,	/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
-	}, {
-		/* An 800x600 72Hz interlaced mode. */
-		"aga800x600", 0,
-		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
-		896, 624, 1,							/* need rows%8 == 0 */
-		896, 624,								/* (cols too) */
-		0x0041, 0x001e,						/* diwstrt h,v */
-		64,						/* 64-bit aligned */
-		BPC2_KILLEHB,							/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x0091,									/* htotal */
-		0x000e,									/* hsstrt */
-		0x001d,									/* hsstop */
-		0x000a,									/* hbstrt */
-		0x001e,									/* hbstop */
-		0x0156,									/* vtotal */
-		0x0001,									/* vsstrt */
-		0x0003,									/* vsstop */
-		0x0000,									/* vbstrt */
-		0x000f,									/* vbstop */
-		0x0050,									/* hcenter */
-		BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
-		BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,	/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
-	},
-	/*
-	 * Additional AGA modes by Geert Uytterhoeven
-	 */
-	{
-		/*
-		 * A 720x400, 70 Hz noninterlaced AGA mode (29.27 kHz)
-		 */
-		"aga720x400", 0,
-		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
-		720, 400, 1,
-		720, 400,
-		0x0041, 0x0013,						/* diwstrt h,v */
-		64,										/* 64-bit aligned */
-		BPC2_KILLEHB,							/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x0079,									/* htotal */
-		0x000e,									/* hsstrt */
-		0x0018,									/* hsstop */
-		0x0001,									/* hbstrt */
-		0x0021,									/* hbstop */
-		0x01a2,									/* vtotal */
-		0x0003,									/* vsstrt */
-		0x0005,									/* vsstop */
-		0x0000,									/* vbstrt */
-		0x0012,									/* vbstop */
-		0x0046,									/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
-		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
-		BMC0_VSYTRUE,							/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
-	}, {
-		/*
-		 * A 640x400, 76 Hz noninterlaced AGA mode (31.89 kHz)
-		 */
-		"aga640x400", 0,
-		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
-		640, 400, 1,
-		640, 400,
-		0x0041, 0x0015,						/* diwstrt h,v */
-		64,										/* 64-bit aligned */
-		BPC2_KILLEHB,							/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x006f,									/* htotal */
-		0x000d,									/* hsstrt */
-		0x0018,									/* hsstop */
-		0x0001,									/* hbstrt */
-		0x0021,									/* hbstop */
-		0x01a4,									/* vtotal */
-		0x0003,									/* vsstrt */
-		0x0005,									/* vsstop */
-		0x0000,									/* vbstrt */
-		0x0014,									/* vbstop */
-		0x0046,									/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
-		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
-		BMC0_VSYTRUE,							/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
-	}, {
-		/*
-		 * A 640x480, 64 Hz noninterlaced AGA mode (31.89 kHz)
-		 */
-		"aga640x480a", 0,
-		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
-		640, 480, 1,
-		640, 480,
-		0x0041, 0x0015,						/* diwstrt h,v */
-		64,										/* 64-bit aligned */
-		BPC2_KILLEHB,							/* bplcon2 */
-		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
-		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
-		0x006f,									/* htotal */
-		0x000e,									/* hsstrt */
-		0x0018,									/* hsstop */
-		0x0001,									/* hbstrt */
-		0x0021,									/* hbstop */
-		0x01f4,									/* vtotal */
-		0x0003,									/* vsstrt */
-		0x0005,									/* vsstop */
-		0x0000,									/* vbstrt */
-		0x0014,									/* vbstop */
-		0x0046,									/* hcenter */
-		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
-		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
-		BMC0_VSYTRUE,							/* beamcon0 */
-		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
-	}
-};
 
-#define	NMODES	(sizeof(mono_modes) / sizeof(struct geometry))
+#define COPLISTSIZE (sizeof(copins)*64)
 
-static struct fb_var_screeninfo mono_mono_amiga_fb_predefined[] = {
-	{ /* autodetect */
-		0, 0, 0, 0, 0, 0, 0, 0,   		/* xres-grayscale */
-		{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, 	/* red green blue tran*/
-		0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }
+enum {
+	cop_wait, cop_bplcon0,
+	cop_spr0ptrh, cop_spr0ptrl,
+	cop_diwstrt, cop_diwstop,
+	cop_diwhigh,
 };
 
-static int mono_num_mono_amiga_fb_predefined= sizeof(mono_mono_amiga_fb_predefined)/sizeof(struct fb_var_screeninfo);
-
-
-
-/* Some default modes */
-#define OCS_PAL_LOWEND_DEFMODE	5	/* PAL non-laced for 500/2000 */
-#define OCS_PAL_3000_DEFMODE		4	/* PAL laced for 3000 */
-#define OCS_NTSC_LOWEND_DEFMODE	1	/* NTSC non-laced for 500/2000 */
-#define OCS_NTSC_3000_DEFMODE		0	/* NTSC laced for 3000 */
-#define AGA_DEFMODE					8	/* 640x480 non-laced for AGA */
-
-static int mono_amifb_inverse = 0;
-static int mono_amifb_mode = -1;
-
-static void mono_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"))
-			mono_amifb_inverse = 1;
-      else if (!strncmp(this_opt, "font:", 5))
-               strcpy(fb_info.fontname, this_opt+5);
-		else
-			for (i = 0; i < NMODES; i++)
-				if (!strcmp(this_opt, mono_modes[i].modename)) {
-					mono_amifb_mode = i;
-					break;
-				}
-}
-
-/* Notes about copper scrolling:
- *
- * 1. The VBLANK routine dynamically rewrites a LIVE copper list that is
- *    currently being executed. Don't mess with it unless you know the
- *    complications. Fairly sure that double buffered lists doesn't
- *    make our life any easier.
- *
- * 2. The vblank code starts executing at logical line 0. Display must be
- *    set up and ready to run by line DIWSTRT_V, typically 0x2c, minimum
- *    value is 0x18 for maximum overscan.
- *
- *    Tests on my A500/030 for dynamically generating a 37 element copper
- *    list during the VBLANK period under AmigaDos required between
- *    0x10 and 0x14 scanlines. This should be pathological case, and
- *    should do better under Linux/68k. It is however IMPERATIVE that I am
- *    first in the VBLANK isr chain. Try to keep 'buildclist' as fast as
- *    possible. Don't think that it justifies assembler thou'
- *
- * 3. PAL 640x256 display (no overscan) has copper-wait y positions in range
- *    0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter
- *    is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff),
- *    WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use
- *    WAIT(0xe2,0xff) to ensure that wrap occurred by next copper
- *    instruction. Argghh!
- *
- * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2].
- *    Horizontal blanking occurs in range 0x0f -> 0x35. Black screen
- *    shown in range 0x04 -> 0x47.
- *
- *    Experiments suggest that using WAIT(0x00,y), we can replace up to
- *    7 bitplane pointers before display fetch start. Using a 
- *    WAIT(0xe0,y-1) instead, we can replace 8 pointers that should be
- *    all that we need for a full AGA display. Should work because of
- *    fetch latency with bitmapped display.
- *
- *    I think that this works. Someone please tell me if something breaks.
- *
- * Is diwstop_h the right value to use for "close to the end of line"?
- * It seems to work for me, at least for the modes I've defined. -wjr
- *
- * I changed the Wait(diwstop_h, 0xff) for 256-line chunk skipping to
- * Wait(diwstop_h-2, 0xff) to make it work with the additional
- * `get-all-you-can-get-out-of-it' AGA modes. Maybe we should derive the
- * wait position from the HTOTAL value? - G.U.
- *
- * The Wait(diwstop_h-2, 0xff) didn't work in Super72 under ECS, instead
- * I changed it to Wait(htotal-4, 0xff). Dunno whether it works under AGA,
- * and don't ask my why it works. I'm trying to get some facts on this issue
- * from Commodore.
- * -Jes
- */
-
-static __inline__ ushort *mono_build_clist_hdr(register struct display *p,
-														ushort *cop,
-														ushort *othercop)	/* Interlace: List for next frame */
-{
-	int i;
-	ushort diwstrt_v = mono_current_par.diwstrt_v;
-	ushort diwstop_h = mono_current_par.diwstop_h;
-
-	if (othercop) {
-		*cop++ = CUSTOM_OFS(cop1lc);
-		*cop++ = (long)othercop >> 16;
-		*cop++ = CUSTOM_OFS(cop1lc) + 2;
-		*cop++ = (long)othercop;
-	}
-
-	/* Point Sprite 0 at cursor sprite: */
-	*cop++ = CUSTOM_OFS(sprpt[0]);
-	*cop++ = (ushort)((long)mono_current_par.cursor >> 16);
-	*cop++ = CUSTOM_OFS(sprpt[0]) + 2;
-	*cop++ = (ushort)((long)mono_current_par.cursor & 0x0000ffff);
-
-	/* Point Sprites 1-7 at dummy sprite: */
-	for (i=1; i<8; i++) {
-		*cop++ = CUSTOM_OFS(sprpt[i]);
-		*cop++ = (ushort)((long)mono_current_par.dummy >> 16);
-		*cop++ = CUSTOM_OFS(sprpt[i]) + 2;
-		*cop++ = (ushort)((long)mono_current_par.dummy & 0x0000ffff);
-	}
-
-	/* Halt copper until we have rebuilt the display list */
-
-	*cop++ = ((diwstrt_v - 2) << 8) | (diwstop_h >> 1) | 0x1;
-	*cop++ = 0xfffe;
-
-	return(cop);
-}
-
-static __inline__ ushort *mono_build_clist_dyn(register struct display *p,
-														ushort *cop,
-														int shf)				/* Interlace: Short frame */
-{
-	ushort diwstrt_v = mono_current_par.diwstrt_v;
-	ushort diwstop_h = mono_current_par.diwstop_h;
-	ushort y_wrap = mono_current_par.y_wrap;
-	ulong offset = y_wrap * mono_current_par.bytes_per_row;
-	long scrmem;
-	int i;
-
-	/* Set up initial bitplane ptrs */
-
-	for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
-		scrmem    = ((long)mono_current_par.bitplane[i]) + offset;
-
-		if (shf)
-			scrmem += mono_current_par.bytes_per_row;
-
-		*cop++ = CUSTOM_OFS(bplpt[i]);
-		*cop++ = (long)scrmem >> 16;
-		*cop++ = CUSTOM_OFS(bplpt[i]) + 2;
-		*cop++ = (long)scrmem;
-	}
-
-	/* If wrapped frame needed - wait for line then switch bitplXs */
-
-	if (y_wrap) {
-		ushort line;
-        
-		if (mono_current_par.bplcon0 & BPC0_LACE)
-			line = diwstrt_v + (mono_current_par.scr_height - y_wrap)/2;
-		else
-			line = diwstrt_v + mono_current_par.scr_height - y_wrap;
-
-		/* Handle skipping over 256-line chunks */
-		while (line > 256) {
-			/* Hardware limitation - 8 bit counter    */
-			/* Wait(diwstop_h-2, 0xff) */
-			if (mono_current_par.bplcon0 & BPC0_SHRES)
-				/*
-				 * htotal-4 is used in SHRES-mode, as diwstop_h-2 doesn't work under ECS.
-				 * Does this work under AGA?
-				 * -Jes
-				 */
-				*cop++ = 0xff00 | ((mono_current_par.htotal-4) | 1);
-			else 
-				*cop++ = 0xff00 | ((diwstop_h-2) >> 1) | 0x1;
-
-			*cop++ = 0xfffe;
-			/* Wait(0, 0) - make sure we're in the new segment */
-			*cop++ = 0x0001;
-			*cop++ = 0xfffe;
-			line -= 256;
+	/*
+	 * Pixel modes for Bitplanes and Sprites
+	 */
 
-			/*
-			 * Under ECS we have to keep color[0], as it is part of a special color-table.
-			 */
+static u_short bplpixmode[3] = {
+	BPC0_SHRES,			/*  35 ns */
+	BPC0_HIRES,			/*  70 ns */
+	0				/* 140 ns */
+};
 
-			if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
-				*cop++ = 0x0180;
-				*cop++ = mono_ecs_color_zero;
-			}
-		}
-	
-		/* Wait(diwstop_h, line - 1) */
-		*cop++ = ((line - 1)   << 8) | (diwstop_h >> 1) | 0x1;
-		*cop++ = 0xfffe;
-
-		for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
-			scrmem = (long)mono_current_par.bitplane[i];
-			if (shf)
-				scrmem += mono_current_par.bytes_per_row;
-
-				*cop++ = CUSTOM_OFS(bplpt[i]); 
-				*cop++ = (long)scrmem >> 16;
-				*cop++ = CUSTOM_OFS(bplpt[i]) + 2;
-				*cop++ = (long)scrmem;
-		}
-	}
-    
-	/* End of Copper list */
-	*cop++ = 0xffff;
-	*cop++ = 0xfffe;
+static u_short sprpixmode[3] = {
+	BPC3_SPRES1 | BPC3_SPRES0,	/*  35 ns */
+	BPC3_SPRES1,			/*  70 ns */
+	BPC3_SPRES0			/* 140 ns */
+};
 
-	return(cop);
-}
+	/*
+	 * Fetch modes for Bitplanes and Sprites
+	 */
 
+static u_short bplfetchmode[3] = {
+	0,				/* 1x */
+	FMODE_BPL32,			/* 2x */
+	FMODE_BPAGEM | FMODE_BPL32	/* 4x */
+};
 
-static __inline__ void mono_build_cursor(register struct display *p)
-{
-	int vs, hs, ve;
-	ushort diwstrt_v = mono_current_par.diwstrt_v;
-	ushort diwstrt_h = mono_current_par.diwstrt_h;
+static u_short sprfetchmode[3] = {
+	0,				/* 1x */
+	FMODE_SPR32,			/* 2x */
+	FMODE_SPAGEM | FMODE_SPR32	/* 4x */
+};
 
-	if (mono_current_par.bplcon0 & BPC0_LACE) {
-		vs = diwstrt_v + (p->cursor_y * p->fontheight)/2; 
-		ve = vs + p->fontheight/2;
-	} else {
-		vs = diwstrt_v + (p->cursor_y * p->fontheight); 
-		ve = vs + p->fontheight;
-	}
+	/*
+	 * Default Colormaps
+	 */
 
-	if (mono_current_par.bplcon0 & BPC0_ECSENA)
-		/*
-		 * It's an AGA mode. We'll assume that the sprite was set
-		 * into 35ns resolution by the appropriate SPRES bits in bplcon3.
-		 */
-		hs = diwstrt_h  * 4 + (p->cursor_x * p->fontwidth) - 4;
-	else
-		hs = diwstrt_h + (p->cursor_x * p->fontwidth) / 2 - 1;
+static u_short red2[] =
+	{ 0x0000, 0xc000 };
+static u_short green2[] =
+	{ 0x0000, 0xc000 };
+static u_short blue2[] =
+	{ 0x0000, 0xc000 };
 
-	if (mono_current_par.bplcon0 & BPC0_ECSENA) {
-		/* There are some high-order bits on the sprite position */
-		*((ulong *) mono_current_par.cursor) =
-		((((vs & 0xff) << 24) | ((vs & 0x100) >> 6) |
-		((vs & 0x200) >> 3)) |
-		(((hs & 0x7f8) << 13) | ((hs & 0x4) >> 2) |
-		((hs & 0x3) << 3)) |
-		(((ve & 0xff) << 8) | ((ve & 0x100) >> 7) |
-		((ve & 0x200) >> 4)));
-	} else {
-		*((ulong *) mono_current_par.cursor) =
-		((vs << 24) | ((vs & 0x00000100) >> 6) |
-		((hs & 0x000001fe) << 15) | (hs & 0x00000001) | 
-		((ve & 0x000000ff) << 8) | ((ve & 0x00000100) >> 7));
-	}
-}
+static u_short red4[] =
+	{ 0x0000, 0xc000, 0x8000, 0xffff };
+static u_short green4[] =
+	{ 0x0000, 0xc000, 0x8000, 0xffff };
+static u_short blue4[] =
+	{ 0x0000, 0xc000, 0x8000, 0xffff };
 
-static void mono_build_ecs_colors(ushort color1, ushort color2, ushort color3, 
-                      ushort color4, ushort *table)
-{
-/*
- * This function calculates the special ECS color-tables needed when running
- * new screen-modes available under ECS. See the hardware reference manual
- * 3rd edition for details.
- * -Jes
- */
-ushort  t;
+static u_short red8[] =
+	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
+static u_short green8[] =
+	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
+static u_short blue8[] =
+	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
 
-        t = (color1 & 0x0ccc);
-        table[0] = t;
-        table[4] = t;
-        table[8] = t;
-        table[12] = t;
-        t = t >> 2;
-        table[0] = (table[0] | t);
-        table[1] = t;
-        table[2] = t;
-        table[3] = t;
-
-        t = (color2 & 0x0ccc);
-        table[1] = (table[1] | t);
-        table[5] = t;
-        table[9] = t;
-        table[13] = t;
-        t = t >> 2;
-        table[4] = (table[4] | t);
-        table[5] = (table[5] | t);
-        table[6] = t;
-        table[7] = t;
-
-        t = (color3 & 0x0ccc);
-        table[2] = (table[2] | t);
-        table[6] = (table[6] | t);
-        table[10] = t;
-        table[14] = t;
-        t = t >> 2;
-        table[8] = (table[8] | t);
-        table[9] = (table[9] | t);
-        table[10] = (table[10] | t);
-        table[11] = t;
-
-        t = (color4 & 0x0ccc);
-        table[3] = (table[3] | t);
-        table[7] = (table[7] | t);
-        table[11] = (table[11] | t);
-        table[15] = t;
-        t = t >> 2;
-        table[12] = (table[12] | t);
-        table[13] = (table[13] | t);
-        table[14] = (table[14] | t);
-        table[15] = (table[15] | t);
+static u_short red16[] =
+	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
+	  0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
+static u_short green16[] =
+	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
+	  0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
+static u_short blue16[] =
+	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
+	  0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
 
-}
 
-/* mono_display_init():
- *
- *    Fills out (struct display *) given a geometry structure
- */
+static struct fb_cmap default_2_colors =
+	{ 0, 2, red2, green2, blue2, NULL };
+static struct fb_cmap default_8_colors =
+	{ 0, 8, red8, green8, blue8, NULL };
+static struct fb_cmap default_4_colors =
+	{ 0, 4, red4, green4, blue4, NULL };
+static struct fb_cmap default_16_colors =
+	{ 0, 16, red16, green16, blue16, NULL };
 
-static void mono_display_init(struct display *p,
-                         struct geometry *geom, ushort inverse)
-{
-	ushort ecs_table[16];
-	int    i;
-	char   *chipptr;
-	ushort diwstrt_v, diwstop_v;
-	ushort diwstrt_h, diwstop_h;
-	ushort diw_min_h, diw_min_v;
-	ushort bplmod, diwstrt, diwstop, diwhigh, ddfstrt, ddfstop;
-	ushort cursorheight, cursormask = 0;
-	u_long size;
-
-	/* Decide colour scheme */
-
-	if (inverse) {
-		mono_current_par.fgcol   = FG_COLOR_INV;
-		mono_current_par.bgcol   = BG_COLOR_INV;
-		mono_current_par.crsrcol = CRSR_COLOR_INV;
-	} else {
-		mono_current_par.fgcol   = FG_COLOR;
-		mono_current_par.bgcol   = BG_COLOR;
-		mono_current_par.crsrcol = CRSR_COLOR;
-	}
-
-	/* Define screen geometry */
-   
-	mono_current_par.scr_max_height = geom->scr_max_height;
-	mono_current_par.scr_max_width  = geom->scr_max_width; 
-	mono_current_par.scr_height     = geom->scr_height;
-	mono_current_par.scr_width      = geom->scr_width;
-	mono_current_par.scr_depth      = geom->scr_depth;
-	mono_current_par.bplcon0        = geom->bplcon0 | BPC0_COLOR;
-	mono_current_par.htotal         = geom->htotal;
+	/*
+	 * Interface used by the world
+	 */
 
-	/* htotal was added, as I use it to calc the pal-line. -Jes */
+void amiga_video_setup(char *options, int *ints);
 
-	if (mono_current_par.scr_depth < 8)
-		mono_current_par.bplcon0 |= (mono_current_par.scr_depth << 12);
-	else {
-		/* must be exactly 8 */
-		mono_current_par.bplcon0 |= BPC0_BPU3;
-	}
+static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
+static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
+static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
+static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
+static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
+static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
+static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+                          u_long arg, int con);
 
-	diw_min_v         = geom->diwstrt_v;
-	diw_min_h         = geom->diwstrt_h;
+static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
+static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
+static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
+static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
+static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
 
-	/* We can derive everything else from this, at least for OCS */
 	/*
-	 * For AGA: we don't use the finer position control available for
-	 * diw* yet (could be set by 35ns increments).
+	 * Interface to the low level console driver
 	 */
 
-	/* Calculate line and plane size while respecting the alignment restrictions */
-	mono_current_par.bytes_per_row  = ((mono_current_par.scr_width+geom->alignment-1)&~(geom->alignment-1)) >> 3;
-	mono_current_par.plane_size     = mono_current_par.bytes_per_row * mono_current_par.scr_height;
-
+struct fb_info *amiga_fb_init(long *mem_start);
+static int amifbcon_switch(int con);
+static int amifbcon_updatevar(int con);
+static void amifbcon_blank(int blank);
 
 	/*
-	 *		Quick hack for frame buffer mmap():
-	 *
-	 *		plane_size must be a multiple of the page size
+	 * Internal routines
 	 */
 
-	mono_current_par.plane_size = PAGE_ALIGN(mono_current_par.plane_size);
-
-
-	mono_current_par.y_wrap   = 0;                  mono_current_par.scroll_latch = 1;
-	p->cursor_x = 0; p->cursor_y = 0; mono_current_par.cursor_latch = 1;
+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 int flash_cursor(void);
+static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static void get_video_mode(const char *name);
+static void check_default_mode(void);
+static u_long chipalloc(u_long size);
+static char *strtoke(char *s,const char *ct);
 
-	if (mono_current_par.bplcon0 & BPC0_LACE) {
-		bplmod = mono_current_par.bytes_per_row;
-		diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/4;
-		diwstop_v = (diwstrt_v + mono_current_par.scr_height/2);
-	} else {
-		bplmod = 0;
-		diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/2;
-		diwstop_v = (diwstrt_v + mono_current_par.scr_height);
-	}
+	/*
+	 * Hardware routines
+	 */
 
-	if (mono_current_par.bplcon0 & BPC0_HIRES) {
-		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/4;
-		diwstop_h = (diwstrt_h + mono_current_par.scr_width/2);
-		/* ??? Where did 0x1d5 come from in original code ??? */
-	} else if (mono_current_par.bplcon0 & BPC0_SHRES) {
-		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/8;
-		diwstop_h = (diwstrt_h + mono_current_par.scr_width/4);
-	} else {
-		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/2;
-		diwstop_h = (diwstrt_h + mono_current_par.scr_width);
-	}
+static int ami_encode_fix(struct fb_fix_screeninfo *fix,
+                          struct amiga_fb_par *par);
+static int ami_decode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par);
+static int ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par);
+static void ami_get_par(struct amiga_fb_par *par);
+static void ami_set_var(struct fb_var_screeninfo *var);
+#ifdef DEBUG
+static void ami_set_par(struct amiga_fb_par *par);
+#endif
+static void ami_pan_var(struct fb_var_screeninfo *var);
+static int ami_update_par(void);
+static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp);
+static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp);
+static void ami_update_display(void);
+static void ami_init_display(void);
+static void ami_do_blank(void);
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
+static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
+static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
+static void ami_set_sprite(void);
+static void ami_init_copper(void);
+static void ami_reinit_copper(void);
+static void ami_build_copper(void);
+static void ami_rebuild_copper(void);
 
-	if (mono_current_par.bplcon0 & BPC0_HIRES) {
-		ddfstrt = (diwstrt_h >> 1) - 4;
-		ddfstop = ddfstrt + (4 * (mono_current_par.bytes_per_row>>1)) - 8;
-	} else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_AGA) {
-		/* There may be some interaction with FMODE here... -8 is magic. */
 
-		/*
-		 * This should be fixed, so it supports all different
-		 * FMODE's.  FMODE varies the speed with 1,2 & 4 the
-		 * standard ECS speed.  Someone else has to do it, as
-		 * I don't have an AGA machine with MMU available
-		 * here.
-		 *
-		 * This particular speed looks like FMODE = 3 to me.
-		 * ddfstop should be changed so it depends on FMODE under AGA.
-		 * -Jes
-		 */
-		ddfstrt = (diwstrt_h >> 1) - 8;
-		ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
-	} else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_ECS){
-		/* 
-		 * Normal speed for ECS, should be the same for FMODE = 0
-		 * -Jes
-		 */
-		ddfstrt = (diwstrt_h >> 1) - 2;
-		ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
-	} else {
-		ddfstrt = (diwstrt_h >> 1) - 8;
-		ddfstop = ddfstrt + (8 * (mono_current_par.bytes_per_row>>1)) - 8;
-	}
+	/*
+	 * External references
+	 */
 
-	if (mono_current_par.bplcon0 & BPC0_LACE)
-		cursorheight = p->fontheight/2;
-	else
-		cursorheight = p->fontheight;
+extern unsigned short ami_intena_vals[];
 
 	/*
-	 *		Quick hack for frame buffer mmap():
-	 *
-	 *		chipptr must be at a page boundary
+	 * Support for Graphics Boards
 	 */
 
-	size = mono_current_par.scr_depth*mono_current_par.plane_size+COP_MEM_REQ+SPR_MEM_REQ+4*(cursorheight-1);
-	size += PAGE_SIZE-1;
-	chipptr = amiga_chip_alloc(size);
-	chipptr = (char *)PAGE_ALIGN((u_long)chipptr);
+#ifdef CONFIG_FB_CYBER			/* Cybervision */
+extern int Cyber_probe(void);
+extern void Cyber_video_setup(char *options, int *ints);
+extern struct fb_info *Cyber_fb_init(long *mem_start);
 
-   
-	/* locate the bitplanes */
-	/* These MUST be 64 bit aligned for full AGA compatibility!! */
+static int amifb_Cyber = 0;
+#endif /* CONFIG_FB_CYBER */
 
-	mono_current_par.smem_start = (u_long)chipptr;
-	mono_current_par.smem_len = mono_current_par.plane_size*mono_current_par.scr_depth;
-	mono_current_par.geometry = geom;
+#ifdef CONFIG_GSP_RESOLVER			/* DMI Resolver */
+extern int resolver_probe(void);
+extern void resolver_video_setup(char *options, int *ints);
+extern struct fb_info *resolver_fb_init(long *mem_start);
 
-	for (i = 0 ; i < mono_current_par.scr_depth ; i++, chipptr += mono_current_par.plane_size) {
-		mono_current_par.bitplane[i] = (u_char *) chipptr;
-		memset ((void *)chipptr, 0, mono_current_par.plane_size);  /* and clear */
-	}
+static int amifb_resolver = 0;
+#endif /* CONFIG_GSP_RESOLVER */
 
-	/* locate the copper lists */
-	mono_current_par.coplist1hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
-	mono_current_par.coplist2hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
+static struct fb_ops amiga_fb_ops = {
+	amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
+	amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
+};
 
-	/* locate the sprite data */
-	mono_current_par.cursor      = (ushort *) chipptr;  chipptr += 8+4*cursorheight;
-	mono_current_par.dummy       = (ushort *) chipptr;  chipptr += 12;
+void amiga_video_setup(char *options, int *ints)
+{
+	char *this_opt;
+	int i;
+	char mcap_spec[80];
 
-	/* create the sprite data for the cursor image */
-	memset((void *)mono_current_par.cursor, 0, 8+4*cursorheight);
 	/*
-	 * Only AGA supplies hires sprites.
+	 * Check for a Graphics Board
 	 */
-	if (mono_current_par.bplcon0 & BPC0_ECSENA && boot_info.bi_amiga.chipset == CS_AGA)
-		/* AGA cursor is SHIRES, ECS sprites differ */
-		for (i = 0; (i < p->fontwidth) && (i < 16); i++)
-			cursormask |= 1<<(15-i);
-	else
-		/* For OCS & ECS sprites are pure LORES 8-< */
-		for (i = 0; (i < p->fontwidth/2) && (i < 8); i++)
-			cursormask |= 1<<(15-i);
-
-	mono_current_par.cursor[0] = mono_cursor_data[0];
-	mono_current_par.cursor[1] = mono_cursor_data[1];
 
-#if (CRSR_BLOCK == 1)
-	for (i = 0; i < cursorheight; i++)
-#else
-	for (i = cursorheight-2; i < cursorheight; i++)
-#endif
-		mono_current_par.cursor[2+2*i] = cursormask;
-
-	/* set dummy sprite data to a blank sprite */
-	memset((void *)mono_current_par.dummy, 0, 12);
-  
-	/* set cursor flashing */
-	mono_current_par.cursor_flash = CRSR_FLASH;
-
-	/* Make the cursor invisible */
-	mono_current_par.cursor_visible = 0;
- 
-	/* Initialise the chipregs */
-	mono_current_par.diwstrt_v = diwstrt_v;
-	mono_current_par.diwstrt_h = diwstrt_h;
-	mono_current_par.diwstop_v = diwstop_v;
-	mono_current_par.diwstop_h = diwstop_h;
-	diwstrt = ((diwstrt_v << 8) | diwstrt_h);
-	diwstop = ((diwstop_v & 0xff) << 8) | (diwstop_h & 0xff);
-
-	custom.bplcon0   = mono_current_par.bplcon0;	/* set the display mode */
-	custom.bplcon1   = 0;		/* Needed for horizontal scrolling */
-	custom.bplcon2   = 0;
-	custom.bpl1mod   = bplmod;
-	custom.bpl2mod   = bplmod;
-	custom.diwstrt   = diwstrt;
-	custom.diwstop   = diwstop;
-	custom.ddfstrt   = ddfstrt;
-	custom.ddfstop   = ddfstop;
-
-	custom.color[0]  = COLOR_MSB(mono_current_par.bgcol);
-	custom.color[1]  = COLOR_MSB(mono_current_par.fgcol);
-	custom.color[17] = COLOR_MSB(mono_current_par.crsrcol); /* Sprite 0 color */
-
-	if (boot_info.bi_amiga.chipset == CS_AGA) {
-		/* Fill in the LSB of the 24 bit color palette */
-		/* Must happen after MSB */
-		custom.bplcon3   = geom->bplcon3 | BPC3_LOCT;
-		custom.color[0]  = COLOR_LSB(mono_current_par.bgcol);
-		custom.color[1]  = COLOR_LSB(mono_current_par.fgcol);
-		custom.color[17] = COLOR_LSB(mono_current_par.crsrcol);
-		custom.bplcon3   = geom->bplcon3;
-	}
-
-	if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
-		/*
-		 * Calculation of the special ECS color-tables for
-		 * planes and sprites is done in the function
-		 * build_ecs_table
-		 */
-
-		/*
-		 * Calcs a special ECS colortable for the bitplane,
-		 * and copies it to the custom registers
-		 */
-		mono_build_ecs_colors(COLOR_MSB(mono_current_par.bgcol), COLOR_MSB(mono_current_par.fgcol),
-				 0, 0, ecs_table); 
-
-#if 0
-		for (i = 0; i < 8; i++){
-			custom.color[i]   = ecs_table[i*2];
-			custom.color[i+8] = ecs_table[i*2+1];
+#ifdef CONFIG_FB_CYBER
+	if (options && *options)
+		if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
+			amifb_Cyber = 1;
+			Cyber_video_setup(options, ints);
+			return;
 		}
-#else
-		for (i = 0; i < 16; i++){
-			custom.color[i]   = ecs_table[i];
+#endif /* CONFIG_FB_CYBER */
+#ifdef CONFIG_GSP_RESOLVER
+	if (options && *options)
+		if (!strncmp(options, "resolver", 5) && resolver_probe()) {
+			amifb_resolver = 1;
+			resolver_video_setup(options, ints);
+			return;
 		}
 #endif
 
-		mono_ecs_color_zero = ecs_table[0];
-
-		/*
-		 * Calcs a special ECS colortable for the cursor
-		 * sprite, and copies it to the appropriate custom
-		 * registers
-		 */
-		mono_build_ecs_colors(0, COLOR_MSB(mono_current_par.crsrcol), 0, 0, ecs_table);
-
-		for (i = 0; i < 16; i++){
-			custom.color[i+16] = ecs_table[i];
-		}
-	}
-
-	if (!(geom->isOCS)) {
-		/* Need to set up a bunch more regs */
-		/* Assumes that diwstrt is in the (0,0) sector, but stop might not be */
-		diwhigh = (diwstop_v & 0x700) | ((diwstop_h & 0x100) << 5);
-
-		custom.bplcon2   = geom->bplcon2;
-		custom.bplcon3   = geom->bplcon3;
-		/* save bplcon3 for blanking */
-		mono_save_bplcon3 = geom->bplcon3;
-
-		custom.diwhigh   = diwhigh;	/* must happen AFTER diwstrt, stop */
-
-		custom.htotal	= geom->htotal;
-		custom.hsstrt	= geom->hsstrt;
-		custom.hsstop	= geom->hsstop;
-		custom.hbstrt	= geom->hbstrt;
-		custom.hbstop	= geom->hbstop;
-		custom.vtotal	= geom->vtotal;
-		custom.vsstrt	= geom->vsstrt;
-		custom.vsstop	= geom->vsstop;
-		custom.vbstrt	= geom->vbstrt;
-		custom.vbstop	= geom->vbstop;
-		custom.hcenter	= geom->hcenter;
-		custom.beamcon0	= geom->beamcon0;
-		if (boot_info.bi_amiga.chipset == CS_AGA) {
-			custom.fmode	= geom->fmode;
-		}
-		/* 
-		 * fmode does NOT! exist under ECS, weird things might happen
-		 */
-
-		/* We could load 8-bit colors here, if we wanted */
-
-		/*
-		 *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-		 */
-		if (boot_info.bi_amiga.chipset != CS_STONEAGE)
-			amiga_audio_min_period = (geom->htotal>>1)+1;
-	}
-
-
-	/* Build initial copper lists. sprites must be set up, and mono_current_par.diwstrt. */
-
-	if (mono_current_par.bplcon0 & BPC0_LACE) {
-		mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, mono_current_par.coplist2hdr),
-		mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
-
-		mono_current_par.coplist2dyn = mono_build_clist_hdr(p,mono_current_par.coplist2hdr, mono_current_par.coplist1hdr),
-		mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
-	} else {
-		mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, NULL),
-		mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
-	}
-
-
-	/* Get ready to run first copper list */
-	custom.cop1lc = mono_current_par.coplist1hdr;
-	custom.copjmp1 = 0;
-
-	/* turn on DMA for bitplane and sprites */
-	custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
-
-	if (mono_current_par.bplcon0 & BPC0_LACE) {
-		/* Make sure we get the fields in the right order */
+	mcap_spec[0] = '\0';
+	fb_info.fontname[0] = '\0';
 
-		/* wait for LOF frame bit to go low */
-		while (custom.vposr & 0x8000)
-			;
+	if (!options || !*options)
+		return;
 
-		/* wait for LOF frame bit to go high */
-		while (!(custom.vposr & 0x8000))
-			;
+	for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
+		char *p;
 
-		/* start again at the beginning of copper list 1 */
-		custom.cop1lc = mono_current_par.coplist1hdr;
-		custom.copjmp1 = 0;
+		if (!strcmp(this_opt, "inverse")) {
+			amifb_inverse = 1;
+			for (i = 0; i < 16; i++) {
+				red16[i] = ~red16[i];
+				green16[i] = ~green16[i];
+				blue16[i] = ~blue16[i];
+			}
+			for (i = 0; i < 8; i++) {
+				red8[i] = ~red8[i];
+				green8[i] = ~green8[i];
+				blue8[i] = ~blue8[i];
+			}
+			for (i = 0; i < 4; i++) {
+				red4[i] = ~red4[i];
+				green4[i] = ~green4[i];
+				blue4[i] = ~blue4[i];
+			}
+			for (i = 0; i < 2; i++) {
+				red2[i] = ~red2[i];
+				green2[i] = ~green2[i];
+				blue2[i] = ~blue2[i];
+			}
+		} else if (!strcmp(this_opt, "ilbm"))
+			amifb_ilbm = 1;
+		else if (!strncmp(this_opt, "monitorcap:", 11))
+			strcpy(mcap_spec, this_opt+11);
+		else if (!strncmp(this_opt, "font:", 5))
+			strcpy(fb_info.fontname, this_opt+5);
+		else if (!strncmp(this_opt, "fstart:", 7))
+			min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "depth:", 6))
+			amiga_fb_predefined[0].bits_per_pixel =
+				simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "size:", 5)) {
+			p = this_opt + 5;
+			if (*p != ';')
+				amiga_fb_predefined[0].xres =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p != ';')
+				amiga_fb_predefined[0].yres =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p != ';')
+				amiga_fb_predefined[0].xres_virtual =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p != ';')
+				amiga_fb_predefined[0].yres_virtual =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p)
+				amiga_fb_predefined[0].bits_per_pixel =
+					simple_strtoul(p, NULL, 0);
+		} else if (!strncmp(this_opt, "timing:", 7)) {
+			p = this_opt + 7;
+			if (*p != ';')
+				amiga_fb_predefined[0].left_margin =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p != ';')
+				amiga_fb_predefined[0].right_margin =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p != ';')
+				amiga_fb_predefined[0].upper_margin =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p)
+				amiga_fb_predefined[0].lower_margin =
+					simple_strtoul(p, NULL, 0);
+		} else if (!strncmp(this_opt, "sync:", 5)) {
+			p = this_opt + 5;
+			if (*p != ';')
+				amiga_fb_predefined[0].hsync_len =
+					simple_strtoul(p, NULL, 0);
+			if (!(p = strchr(p, ';')))
+				continue;
+			if (*++p)
+				amiga_fb_predefined[0].vsync_len =
+					simple_strtoul(p, NULL, 0);
+		} else
+			get_video_mode(this_opt);
 	}
-}
 
+	if (min_fstrt < 48)
+		min_fstrt = 48;
 
-static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data)
-{
-	register struct display *p = disp;
-
-	static ushort cursorcount = 0;
-	static ushort cursorstate = 0;
+	if (*mcap_spec) {
+		char *p;
+		int vmin, vmax, hmin, hmax;
 
-	/* I *think* that you should only change display lists on long frame.
-	 * At least it goes awfully peculiar on my A500 without the following
-	 * test. Not really in a position to test this hypothesis, so sorry
-	 * for the slow scrolling, all you flicker-fixed souls
+	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+	 * <V*> vertical freq. in Hz
+	 * <H*> horizontal freq. in kHz
 	 */
 
-	if (!(mono_current_par.bplcon0 & BPC0_LACE) || (custom.vposr & 0x8000)) {
-		if (mono_current_par.scroll_latch || mono_current_par.cursor_latch)
-			mono_build_cursor(p);
-
-		if (mono_current_par.scroll_latch)
-			if (mono_current_par.bplcon0 & BPC0_LACE) {
-				mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
-				mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
-			} else
-				mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
-			mono_current_par.scroll_latch = 0;
-			mono_current_par.cursor_latch = 0;
-	}
-
-	if (!(custom.potgor & (1<<10)))
-		mono_vblank.right_count++;
-
-	if (mono_current_par.cursor_visible) {
-		if (mono_current_par.cursor_flash) {
-			if (cursorcount)
-				cursorcount--;
-			else {
-				cursorcount = CRSR_RATE;
-				if ((cursorstate = !cursorstate))
-					custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
-				else
-					custom.dmacon = DMAF_SPRITE;
-			}
-		}
-	} else
-		custom.dmacon = DMAF_SPRITE;
-
-	if (mono_do_blank) {
-		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
-		custom.color[0] = 0;
-		if (boot_info.bi_amiga.chipset == CS_AGA) {
-			/* Fill in the LSB of the 24 bit color palette */
-			/* Must happen after MSB */
-			custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
-			custom.color[0]= 0;
-			custom.bplcon3 = mono_save_bplcon3;
-		}
-		mono_do_blank = 0;
-	}
-
-	if (mono_do_unblank) {
-		if (mono_current_par.cursor_visible)
-			custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
-		else
-			custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
-		custom.color[0] = COLOR_MSB(mono_current_par.bgcol);
-		if (boot_info.bi_amiga.chipset == CS_AGA) {
-			/* Fill in the LSB of the 24 bit color palette */
-			/* Must happen after MSB */
-			custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
-			custom.color[0] = COLOR_LSB(mono_current_par.bgcol);
-			custom.bplcon3 = mono_save_bplcon3;
-		}
-		/* color[0] is set to mono_ecs_color_zero under ECS */
-		if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
-			custom.color[0]  = mono_ecs_color_zero;
-		}
-		mono_do_unblank = 0;
+		if (!(p = strtoke(mcap_spec, ";")) || !*p)
+			goto cap_invalid;
+		vmin = simple_strtoul(p, NULL, 10);
+		if (vmin <= 0)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, ";")) || !*p)
+			goto cap_invalid;
+		vmax = simple_strtoul(p, NULL, 10);
+		if (vmax <= 0 || vmax <= vmin)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, ";")) || !*p)
+			goto cap_invalid;
+		hmin = 1000 * simple_strtoul(p, NULL, 10);
+		if (hmin <= 0)
+			goto cap_invalid;
+		if (!(p = strtoke(NULL, "")) || !*p)
+			goto cap_invalid;
+		hmax = 1000 * simple_strtoul(p, NULL, 10);
+		if (hmax <= 0 || hmax <= hmin)
+			goto cap_invalid;
+
+		vfmin = vmin;
+		vfmax = vmax;
+		hfmin = hmin;
+		hfmax = hmax;
+cap_invalid:
+		;
 	}
-
-	mono_vblank.done = 1;
 }
 
-
-static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-	int i;
-
-	strcpy(fix->id, mono_current_par.geometry->modename);
-	fix->smem_start = mono_current_par.smem_start;
-	fix->smem_len = mono_current_par.smem_len;
-
 	/*
-	 *		Only monochrome bitmap at the moment
+	 * Get the Fixed Part of the Display
 	 */
 
-	fix->type = FB_TYPE_PACKED_PIXELS;
-
-	fix->type_aux = 0;
-	if (mono_amifb_inverse)
-		fix->visual = FB_VISUAL_MONO10;
-	else
-		fix->visual = FB_VISUAL_MONO01;
-
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 1;
-
-	fix->line_length = 0;
-	for (i = 0; i < arraysize(fix->reserved); i++)
-		fix->reserved[i] = 0;
-	return(0);
-}
-
-
-static int mono_amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
+static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
 {
-	int i;
-
-	var->xres = mono_current_par.geometry->scr_width;
-	var->yres = mono_current_par.geometry->scr_height;
-	var->xres_virtual = var->xres;
-	var->yres_virtual = var->yres;
-	var->xoffset = 0;
-	var->yoffset = 0;
+	struct amiga_fb_par par;
 
-	var->bits_per_pixel = mono_current_par.geometry->scr_depth;
-	var->grayscale = 0;
+	if (con == -1)
+		ami_get_par(&par);
+	else {
+		int err;
 
-	if (boot_info.bi_amiga.chipset == CS_AGA) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->red.msb_right = 0;
-		var->green = var->red;
-		var->blue = var->red;
-	} else {
-		var->red.offset = 0;
-		var->red.length = 4;
-		var->red.msb_right = 0;
-		var->green = var->red;
-		var->blue = var->red;
+		if ((err = ami_decode_var(&disp[con].var, &par)))
+			return err;
 	}
-
-	var->nonstd = 0;
-	var->activate = 0;
-
-	var->width = -1;
-	var->height = -1;
-
-	var->accel = FB_ACCEL_NONE;
-
-	var->pixclock = 35242;
-	var->left_margin = (mono_current_par.geometry->hbstop-mono_current_par.geometry->hsstrt)*8;
-	var->right_margin = (mono_current_par.geometry->hsstrt-mono_current_par.geometry->hbstrt)*8;
-	var->upper_margin = (mono_current_par.geometry->vbstop-mono_current_par.geometry->vsstrt)*8;
-	var->lower_margin = (mono_current_par.geometry->vsstrt-mono_current_par.geometry->vbstrt)*8;
-	var->hsync_len = (mono_current_par.geometry->hsstop-mono_current_par.geometry->hsstrt)*8;
-	var->vsync_len = (mono_current_par.geometry->vsstop-mono_current_par.geometry->vsstrt)*8;
-	var->sync = 0;
-	if (mono_current_par.geometry->bplcon0 & BPC0_LACE)
-		var->vmode = FB_VMODE_INTERLACED;
-	else if ((boot_info.bi_amiga.chipset == CS_AGA) && (mono_current_par.geometry->fmode & FMODE_BSCAN2))
-		var->vmode = FB_VMODE_DOUBLE;
-	else
-		var->vmode = FB_VMODE_NONINTERLACED;
-
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-
-	return(0);
+	return ami_encode_fix(fix, &par);
 }
 
+	/*
+	 * Get the User Defined Part of the Display
+	 */
 
-static void mono_amiga_fb_set_disp(int con)
+static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
 {
-	struct fb_fix_screeninfo fix;
+	int err = 0;
 
-	mono_amiga_fb_get_fix(&fix, con);
-	if (con == -1)
-		con = 0;
-	disp[con].screen_base = (u_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].line_length = fix.line_length;
-	disp[con].can_soft_blank = 1;
-	disp[con].inverse = mono_amifb_inverse;
-}
+	if (con == -1) {
+		struct amiga_fb_par par;
 
+		ami_get_par(&par);
+		err = ami_encode_var(var, &par);
+	} else
+		*var = disp[con].var;
+	return err;
+}
 
-static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
 	/*
-	 *		Not yet implemented
+	 * Set the User Defined Part of the Display
 	 */
-	return 0;				/* The X server needs this */
-	return(-EINVAL);
-}
-
-
-static short mono_red_normal[] = {
-	((BG_COLOR & 0xff0000)>>8) | ((BG_COLOR & 0xff0000)>>16),
-	((FG_COLOR & 0xff0000)>>8) | ((FG_COLOR & 0xff0000)>>16)
-};
-static short mono_green_normal[] = {
-	((BG_COLOR & 0x00ff00)) | ((BG_COLOR & 0x00ff00)>>8),
-	((FG_COLOR & 0x00ff00)) | ((FG_COLOR & 0x00ff00)>>8)
-};
-static short mono_blue_normal[] = {
-	((BG_COLOR & 0x0000ff)<<8) | ((BG_COLOR & 0x0000ff)),
-	((FG_COLOR & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
-};
 
-static short mono_red_inverse[] = {
-	((BG_COLOR_INV & 0xff0000)>>8) | ((BG_COLOR_INV & 0xff0000)>>16),
-	((FG_COLOR_INV & 0xff0000)>>8) | ((FG_COLOR_INV & 0xff0000)>>16)
-};
-static short mono_green_inverse[] = {
-	((BG_COLOR_INV & 0x00ff00)) | ((BG_COLOR_INV & 0x00ff00)>>8),
-	((FG_COLOR_INV & 0x00ff00)) | ((FG_COLOR_INV & 0x00ff00)>>8)
-};
-static short mono_blue_inverse[] = {
-	((BG_COLOR_INV & 0x0000ff)<<8) | ((BG_COLOR_INV & 0x0000ff)),
-	((FG_COLOR_INV & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
-};
-
-static struct fb_cmap mono_default_cmap_normal = { 0, 2, mono_red_normal, mono_green_normal, mono_blue_normal, NULL };
-static struct fb_cmap mono_default_cmap_inverse = { 0, 2, mono_red_inverse, mono_green_inverse, mono_blue_inverse, NULL };
-
-static int mono_amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
 {
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned int hred, hgreen, hblue, htransp;
-	struct fb_cmap *def_cmap;
+	int err, activate = var->activate;
+	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+	struct amiga_fb_par par;
 
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-	if (start < 0)
-		return(-EINVAL);
 
-	if (mono_amifb_inverse)
-		def_cmap = &mono_default_cmap_inverse;
-	else
-		def_cmap = &mono_default_cmap_normal;
+	/*
+	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+	 * as FB_VMODE_SMOOTH_XPAN is only used internally
+	 */
 
-	for (i = 0; i < cmap->len; i++) {
-		if (i < def_cmap->len) {
-			hred = def_cmap->red[i];
-			hgreen = def_cmap->green[i];
-			hblue = def_cmap->blue[i];
-			if (def_cmap->transp)
-				htransp = def_cmap->transp[i];
-			else
-				htransp = 0;
-		} else
-			hred = hgreen = hblue = htransp = 0;
-		if (kspc) {
-			*red = hred;
-			*green = hgreen;
-			*blue = hblue;
-			if (transp)
-				*transp = htransp;
-		} else {
-			put_fs_word(hred, red);
-			put_fs_word(hgreen, green);
-			put_fs_word(hblue, blue);
-			if (transp)
-				put_fs_word(htransp, transp);
+	if (var->vmode & FB_VMODE_CONUPDATE) {
+		var->vmode |= FB_VMODE_YWRAP;
+		var->xoffset = disp[con].var.xoffset;
+		var->yoffset = disp[con].var.yoffset;
+	}
+	if ((err = ami_decode_var(var, &par)))
+		return err;
+	ami_encode_var(var, &par);
+	if ((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) {
+			struct fb_fix_screeninfo fix;
+
+			ami_encode_fix(&fix, &par);
+			disp[con].screen_base = (u_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].line_length = fix.line_length;
+			disp[con].can_soft_blank = 1;
+			disp[con].inverse = amifb_inverse;
+			if (fb_info.changevar)
+				(*fb_info.changevar)(con);
 		}
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
+		if (oldbpp != var->bits_per_pixel) {
+			if ((err = alloc_cmap(&disp[con].cmap, 0, 0)))
+				return err;
+			do_install_cmap(con);
+		}
+		if (con == currcon)
+			ami_set_var(&disp[con].var);
 	}
-	return(0);
+	return 0;
 }
 
-
-static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	/*
-	 *		Not yet implemented
-	 */
-	return(-EINVAL);
-}
-
-
-static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
 	/*
-	 *		Not yet implemented
+	 * Pan or Wrap the Display
+	 *
+	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 	 */
-	return(-EINVAL);
-}
-
-
-static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-								  unsigned long arg, int con)
-{
-	return(-EINVAL);
-}
-
-static struct fb_ops mono_amiga_fb_ops = {
-	mono_amiga_fb_get_fix, mono_amiga_fb_get_var, mono_amiga_fb_set_var, mono_amiga_fb_get_cmap,
-	mono_amiga_fb_set_cmap, mono_amiga_fb_pan_display, mono_amiga_fb_ioctl	
-};
-
 
-static int mono_amifb_switch (int con)
-{
-	mono_current_par.y_wrap = disp[con].var.yoffset;
-	mono_current_par.cursor_latch = 1;
-	mono_current_par.scroll_latch = 1;
-	return(0);
-}
-
-
-static int mono_amifb_updatevar(int con)
+static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
 {
-	mono_current_par.y_wrap = disp[con].var.yoffset;
-	mono_current_par.cursor_latch = 1;
-	mono_current_par.scroll_latch = 1;
-	return(0);
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset<0 || var->yoffset >= disp[con].var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	} else {
+		/*
+		 * TODO: There will be problems when xpan!=1, so some columns
+		 * on the right side will never be seen
+		 */
+		if (var->xoffset+disp[con].var.xres > upx(16<<maxfmode, disp[con].var.xres_virtual) ||
+		    var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
+			return -EINVAL;
+	}
+	if (con == currcon)
+		ami_pan_var(var);
+	disp[con].var.xoffset = var->xoffset;
+	disp[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		disp[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		disp[con].var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
 }
 
+	/*
+	 * Get the Colormap
+	 */
 
-static void mono_amifb_blank(int blank)
+static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
 {
-	if (blank)
-		mono_do_blank = 1;
+	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
-		mono_do_unblank = 1;
+		copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
+		          cmap, kspc ? 0 : 2);
+	return 0;
 }
 
+	/*
+	 * Set the Colormap
+	 */
 
-static struct fb_info *mono_amiga_fb_init(long *mem_start)
+static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
 {
-	int mode = mono_amifb_mode;
-	ulong model;
-	int inverse_video = mono_amifb_inverse;
 	int err;
 
-	err=register_framebuffer("Amiga Builtin", &node, &mono_amiga_fb_ops,  mono_num_mono_amiga_fb_predefined,
-									 mono_mono_amiga_fb_predefined);
-
-	model = boot_info.bi_un.bi_ami.model;
-	if (mode == -1)
-		if (boot_info.bi_amiga.chipset == CS_AGA)
-			mode = AGA_DEFMODE;
-		else if (model == AMI_3000)
-			mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_3000_DEFMODE : OCS_NTSC_3000_DEFMODE;
-		else
-			mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_LOWEND_DEFMODE : OCS_NTSC_LOWEND_DEFMODE;
-
-	mono_init_vblank();
-	mono_display_init(disp, &mono_modes[mode], inverse_video);
-	if (!add_isr(IRQ_AMIGA_VERTB, mono_amifb_interrupt, 0, NULL, "frame buffer"))
-		panic("Couldn't add vblank interrupt");
-
-	mono_amiga_fb_get_var(&disp[0].var, 0);
-	if (mono_amifb_inverse)
-		disp[0].cmap = mono_default_cmap_inverse;
+	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
-		disp[0].cmap = mono_default_cmap_normal;
-	mono_amiga_fb_set_disp(-1);
-
-	strcpy(fb_info.modename, "Amiga Builtin ");
-	fb_info.disp = disp;
-	fb_info.switch_con = &mono_amifb_switch;
-	fb_info.updatevar = &mono_amifb_updatevar;
-	fb_info.blank = &mono_amifb_blank;	
-	strcat(fb_info.modename, mono_modes[mode].modename);
-
-	return(&fb_info);
+		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
+	return 0;
 }
-#endif /* USE_MONO_AMIFB_IF_NON_AGA */
-
 
-/* -------------------- OCS specific routines ------------------------------- */
-
-
-#ifdef CONFIG_AMIFB_OCS
-   /*
-    *    Initialization
-    *
-    *    Allocate the required chip memory.
-    *    Set the default video mode for this chipset. If a video mode was
-    *    specified on the command line, it will override the default mode.
-    */
+	/*
+	 * Amiga Frame Buffer Specific ioctls
+	 */
 
-static int ocs_init(void)
+static int amiga_fb_ioctl(struct inode *inode, struct file *file,
+                          u_int cmd, u_long arg, int con)
 {
-   u_long p;
-
-   /*
-    *    Disable Display DMA
-    */
-
-   custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-   /*
-    *    Set the Default Video Mode
-    */
-
-   if (!amifb_mode)
-      amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
-                                  DEFMODE_PAL : DEFMODE_NTSC);
-
-   /*
-    *    Allocate Chip RAM Structures
-    */
-
-   videomemorysize = VIDEOMEMSIZE_OCS;
+	int i;
 
+	switch (cmd) {
+		case FBIOGET_FCURSORINFO : {
+			struct fb_fix_cursorinfo crsrfix;
+			
+			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
+			if (!i) {
+				i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
+				memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix));
+			}
+			return i;
+		}
+		case FBIOGET_VCURSORINFO : {
+			struct fb_var_cursorinfo crsrvar;
 
-   ...
-   ...
-   ...
+			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
+			if (!i) {
+				i = amiga_fb_get_var_cursorinfo(&crsrvar,
+					((struct fb_var_cursorinfo *)arg)->data, con);
+				memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar));
+			}
+			return i;
+		}
+		case FBIOPUT_VCURSORINFO : {
+			struct fb_var_cursorinfo crsrvar;
 
+			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
+			if (!i) {
+				memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar));
+				i = amiga_fb_set_var_cursorinfo(&crsrvar,
+					((struct fb_var_cursorinfo *)arg)->data, con);
+			}
+			return i;
+		}
+		case FBIOGET_CURSORSTATE : {
+			struct fb_cursorstate crsrstate;
 
-   /*
-    *    Enable Display DMA
-    */
+			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
+			if (!i) {
+				i = amiga_fb_get_cursorstate(&crsrstate, con);
+				memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate));
+			}
+			return i;
+		}
+		case FBIOPUT_CURSORSTATE : {
+			struct fb_cursorstate crsrstate;
 
-   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                   DMAF_SPRITE;
+			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
+			if (!i) {
+				memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate));
+				i = amiga_fb_set_cursorstate(&crsrstate, con);
+			}
+			return i;
+		}
+#ifdef DEBUG
+		case FBCMD_GET_CURRENTPAR : {
+			struct amiga_fb_par par;
+
+			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amiga_fb_par));
+			if (!i) {
+				ami_get_par(&par);
+				memcpy_tofs((void *)arg, &par, sizeof(struct amiga_fb_par));
+			}
+			return i;
+		}
+		case FBCMD_SET_CURRENTPAR : {
+			struct amiga_fb_par par;
 
-   return(0);
+			i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amiga_fb_par));
+			if (!i) {
+				memcpy_fromfs(&par, (void *)arg, sizeof(struct amiga_fb_par));
+				ami_set_par(&par);
+			}
+			return i;
+		}
+#endif */ DEBUG */
+	}
+	return -EINVAL;
 }
-#endif /* CONFIG_AMIFB_OCS */
 
+	/*
+	 * Hardware Cursor
+	 */
 
-/* -------------------- ECS specific routines ------------------------------- */
-
-
-#ifdef CONFIG_AMIFB_ECS
-   /*
-    *    Initialization
-    *
-    *    Allocate the required chip memory.
-    *    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 ecs_init(void)
+static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
 {
-   u_long p;
-
-   /*
-    *    Disable Display DMA
-    */
-
-   custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-   /*
-    *    Set the Default Video Mode
-    */
-
-   if (!amifb_mode)
-      if (AMIGAHW_PRESENT(AMBER_FF))
-         amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
-                                     DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
-      else
-         amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
-                                     DEFMODE_PAL : DEFMODE_NTSC);
-
-   /*
-    *    Allocate Chip RAM Structures
-    */
-
-   if (boot_info.bi_amiga.chip_size > 1048576)
-      videomemorysize = VIDEOMEMSIZE_ECS_2M;
-   else
-      videomemorysize = VIDEOMEMSIZE_ECS_1M;
-
-
-   ...
-   ...
-   ...
-
-
-   /*
-    *    Enable Display DMA
-    */
-
-   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                   DMAF_SPRITE;
-
-   return(0);
-}
-#endif /* CONFIG_AMIFB_ECS */
-
-
-/* -------------------- AGA specific routines ------------------------------- */
-
-
-#ifdef CONFIG_AMIFB_AGA
-   /*
-    *    Macros for the conversion from real world values to hardware register
-    *    values (and vice versa).
-    *
-    *    This helps us to keep our attention on the real stuff...
-    *
-    *    Hardware limits:
-    *
-    *       parameter     min      max     step
-    *       ---------     ---     ----     ----
-    *       diwstrt_h       0     2047        1
-    *       diwstrt_v       0     2047        1
-    *       diwstop_h       0     2047        1
-    *       diwstop_v       0     2047        1
-    *
-    *       ddfstrt         0     2032       16
-    *       ddfstop         0     2032       16
-    *
-    *       htotal          8     2048        8
-    *       hsstrt          0     2040        8
-    *       hsstop          0     2040        8
-    *       vtotal          1     2048        1
-    *       vsstrt          0     2047        1
-    *       vsstop          0     2047        1
-    *       hcenter         0     2040        8
-    *
-    *       hbstrt          0     2047        1
-    *       hbstop          0     2047        1
-    *       vbstrt          0     2047        1
-    *       vbstop          0     2047        1
-    *
-    *    Horizontal values are in 35 ns (SHRES) pixels
-    *    Vertical values are in scanlines
-    */
-
-/* bplcon1 (smooth scrolling) */
-
-#define hscroll2hw(hscroll) \
-   (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
-    ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
-
-#define hw2hscroll(hscroll) \
-   (((hscroll)>>8 & 0x00c3) | ((hscroll)<<2 & 0x003c))
-
-/* diwstrt/diwstop/diwhigh (visible display window) */
-
-#define diwstrt2hw(diwstrt_h, diwstrt_v) \
-   (((diwstrt_v)<<8 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
-#define diwstop2hw(distop_h, diwstop_v) \
-   (((diwstop_v)<<8 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
-#define diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v) \
-   (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
-    ((diwstop_v) & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
-    ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>8 & 0x0007))
-
-#define hw2diwstrt_h(diwstrt, diwhigh) \
-   (((diwhigh)<<5 & 0x0400) | ((diwstrt)<<2 & 0x03fc) | ((diwhigh)>>3 & 0x0003))
-#define hw2diwstrt_v(diwstrt, diwhigh) \
-   (((diwhigh)<<8 & 0x0700) | ((diwstrt)>>8 & 0x00ff))
-#define hw2diwstop_h(diwstop, diwhigh) \
-   (((diwhigh)>>3 & 0x0400) | ((diwstop)<<2 & 0x03fc) | \
-    ((diwhigh)>>11 & 0x0003))
-#define hw2diwstop_v(diwstop, diwhigh) \
-   (((diwhigh) & 0x0700) | ((diwstop)>>8 & 0x00ff))
-
-/* ddfstrt/ddfstop (display DMA) */
-
-#define ddfstrt2hw(ddfstrt)   (div8(ddfstrt) & 0x00fe)
-#define ddfstop2hw(ddfstop)   (div8(ddfstop) & 0x00fe)
-
-#define hw2ddfstrt(ddfstrt)   ((ddfstrt)<<3)
-#define hw2ddfstop(ddfstop)   ((ddfstop)<<3)
-
-/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal (sync timings) */
-
-#define hsstrt2hw(hsstrt)     (div8(hsstrt))
-#define hsstop2hw(hsstop)     (div8(hsstop))
-#define htotal2hw(htotal)     (div8(htotal)-1)
-#define vsstrt2hw(vsstrt)     (vsstrt)
-#define vsstop2hw(vsstop)     (vsstop)
-#define vtotal2hw(vtotal)     ((vtotal)-1)
-
-#define hw2hsstrt(hsstrt)     ((hsstrt)<<3)
-#define hw2hsstop(hsstop)     ((hsstop)<<3)
-#define hw2htotal(htotal)     (((htotal)+1)<<3)
-#define hw2vsstrt(vsstrt)     (vsstrt)
-#define hw2vsstop(vsstop)     (vsstop)
-#define hw2vtotal(vtotal)     ((vtotal)+1)
-
-/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
-
-#define hbstrt2hw(hbstrt)     (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
-#define hbstop2hw(hbstop)     (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
-#define vbstrt2hw(vbstrt)     (vbstrt)
-#define vbstop2hw(vbstop)     (vbstop)
-
-#define hw2hbstrt(hbstrt)     (((hbstrt)<<3 & 0x07f8) | ((hbstrt)>>8 & 0x0007))
-#define hw2hbstop(hbstop)     (((hbstop)<<3 & 0x07f8) | ((hbstop)>>8 & 0x0007))
-#define hw2vbstrt(vbstrt)     (vbstrt)
-#define hw2vbstop(vbstop)     (vbstop)
-
-/* color */
-
-#define rgb2hw_high(red, green, blue) \
-   (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
-#define rgb2hw_low(red, green, blue) \
-   (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
-
-#define hw2red(high, low)     (((high)>>4 & 0xf0) | ((low)>>8 & 0x0f))
-#define hw2green(high, low)   (((high) & 0xf0) | ((low)>>4 & 0x0f))
-#define hw2blue(high, low)    (((high)<<4 & 0xf0) | ((low) & 0x0f))
-
-/* sprpos/sprctl (sprite positioning) */
-
-#define spr2hw_pos(start_v, start_h) \
-   (((start_v)<<8&0xff00) | ((start_h)>>3&0x00ff))
-#define spr2hw_ctl(start_v, start_h, stop_v) \
-   (((stop_v)<<8&0xff00) | ((start_v)>>3&0x0040) | ((stop_v)>>4&0x0020) | \
-    ((start_h)<<3&0x0018) | ((start_v)>>6&0x0004) | ((stop_v)>>7&0x0002) | \
-    ((start_h)>>2&0x0001))
-
-
-   /*
-    *    Hardware Cursor
-    */
-
-struct aga_cursorsprite {
-   u_short sprpos;
-   u_short pad1[3];
-   u_short sprctl;
-   u_short pad2[3];
-   union {
-      struct {
-         u_long data[64*4];
-         u_long trailer[4];
-      } nonlaced;
-      struct {
-         u_long data[32*4];
-         u_long trailer[4];
-      } laced;
-   } u;
-};
-
-struct aga_dummysprite {
-   u_short sprpos;
-   u_short pad1[3];
-   u_short sprctl;
-   u_short pad2[3];
-   u_long data[4];
-   u_long trailer[4];
-};
-
+	return ami_get_fix_cursorinfo(fix, con);
+}
 
-   /*
-    *    Pixel modes for Bitplanes and Sprites
-    */
+static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+{
+	return ami_get_var_cursorinfo(var, data, con);
+}
 
-static u_short bplpixmode[3] = {
-   BPC0_SHRES,                   /*  35 ns / 28 MHz */
-   BPC0_HIRES,                   /*  70 ns / 14 MHz */
-   0                             /* 140 ns /  7 MHz */
-};
+static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+{
+	return ami_set_var_cursorinfo(var, data, con);
+}
 
-static u_short sprpixmode[3] = {
-   BPC3_SPRES1 | BPC3_SPRES0,    /*  35 ns / 28 MHz */
-   BPC3_SPRES1,                  /*  70 ns / 14 MHz */
-   BPC3_SPRES0                   /* 140 ns /  7 MHz */
-};
+static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
+{
+	return ami_get_cursorstate(state, con);
+}
 
+static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
+{
+	return ami_set_cursorstate(state, con);
+}
 
-   /*
-    *    Initialization
-    *
-    *    Allocate the required chip memory.
-    *    Set the default video mode for this chipset. If a video mode was
-    *    specified on the command line, it will override the default mode.
-    */
+	/*
+	 * Initialisation
+	 */
 
-static int aga_init(void)
+struct fb_info *amiga_fb_init(long *mem_start)
 {
-   u_long p;
+	int err, tag, i;
+	u_long chipptr;
 
-   /*
-    *    Disable Display DMA
-    */
+	/*
+	 * Check for a Graphics Board
+	 */
 
-   custom.dmacon = DMAF_ALL | DMAF_MASTER;
+#ifdef CONFIG_FB_CYBER
+	if (amifb_Cyber)
+		return Cyber_fb_init(mem_start);
+#endif /* CONFIG_FB_CYBER */
+#ifdef CONFIG_GSP_RESOLVER
+	if (amifb_resolver){
+		custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+				DMAF_BLITTER | DMAF_SPRITE;
+		return NULL;
+	}
+#endif
 
-   /*
-    *    Set the Default Video Mode
-    */
+	/*
+	 * Use the Builtin Chipset
+	 */
 
-   if (!amifb_mode)
-      amifb_mode = get_video_mode(DEFMODE_AGA);
+	if (!AMIGAHW_PRESENT(AMI_VIDEO))
+		return NULL;
 
-   /*
-    *    Allocate Chip RAM Structures
-    */
+	custom.dmacon = DMAF_ALL | DMAF_MASTER;
 
-   if (boot_info.bi_amiga.chip_size > 1048576)
-      videomemorysize = VIDEOMEMSIZE_AGA_2M;
-   else
-      videomemorysize = VIDEOMEMSIZE_AGA_1M;
+	switch (boot_info.bi_amiga.chipset) {
+#ifdef CONFIG_AMIFB_OCS
+		case CS_OCS:
+			strcat(amiga_fb_name, "OCS");
+default_chipset:
+			chipset = TAG_OCS;
+			maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
+			maxdepth[TAG_HIRES] = 4;
+			maxdepth[TAG_LORES] = 6;
+			maxfmode = TAG_FMODE_1;
+			if (!amifb_usermode)		/* Set the Default Video Mode */
+				get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+				               DEFMODE_PAL : DEFMODE_NTSC);
+			videomemorysize = VIDEOMEMSIZE_OCS;
+			break;
+#endif /* CONFIG_AMIFB_OCS */
 
-   p = chipalloc(videomemorysize+                     /* Bitplanes */
-                 sizeof(struct clist_hdr)+            /* Copper Lists */
-                 2*sizeof(struct clist_dyn)+
-                 2*sizeof(struct aga_cursorsprite)+   /* Sprites */
-                 sizeof(struct aga_dummysprite));
+#ifdef CONFIG_AMIFB_ECS
+		case CS_ECS:
+			strcat(amiga_fb_name, "ECS");
+			chipset = TAG_ECS;
+			maxdepth[TAG_SHRES] = 2;
+			maxdepth[TAG_HIRES] = 4;
+			maxdepth[TAG_LORES] = 6;
+			maxfmode = TAG_FMODE_1;
+			if (!amifb_usermode) {		/* Set the Default Video Mode */
+				if (AMIGAHW_PRESENT(AMBER_FF))
+					get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+					               DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
+				else
+					get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+					               DEFMODE_PAL : DEFMODE_NTSC);
+			}
+			if (boot_info.bi_amiga.chip_size > 1048576)
+				videomemorysize = VIDEOMEMSIZE_ECS_2M;
+			else
+				videomemorysize = VIDEOMEMSIZE_ECS_1M;
+			break;
+#endif /* CONFIG_AMIFB_ECS */
 
-   assignchunk(videomemory, u_long, p, videomemorysize);
-   assignchunk(clist_hdr, struct clist_hdr *, p, sizeof(struct clist_hdr));
-   assignchunk(clist_lof, struct clist_dyn *, p, sizeof(struct clist_dyn));
-   assignchunk(clist_shf, struct clist_dyn *, p, sizeof(struct clist_dyn));
-   assignchunk(lofsprite, u_long *, p, sizeof(struct aga_cursorsprite));
-   assignchunk(shfsprite, u_long *, p, sizeof(struct aga_cursorsprite));
-   assignchunk(dummysprite, u_long *, p, sizeof(struct aga_dummysprite));
+#ifdef CONFIG_AMIFB_AGA
+		case CS_AGA:
+			strcat(amiga_fb_name, "AGA");
+			chipset = TAG_AGA;
+			maxdepth[TAG_SHRES] = 8;
+			maxdepth[TAG_HIRES] = 8;
+			maxdepth[TAG_LORES] = 8;
+			maxfmode = TAG_FMODE_4;
+			if (!amifb_usermode)		/* Set the Default Video Mode */
+				get_video_mode(DEFMODE_AGA);
+			if (boot_info.bi_amiga.chip_size > 1048576)
+				videomemorysize = VIDEOMEMSIZE_AGA_2M;
+			else
+				videomemorysize = VIDEOMEMSIZE_AGA_1M;
+			break;
+#endif /* CONFIG_AMIFB_AGA */
 
-   /*
-    *    Make sure the Copper has something to do
-    */
+		default:
+#ifdef CONFIG_AMIFB_OCS
+			printk("Unknown graphics chipset, defaulting to OCS\n");
+			strcat(amiga_fb_name, "Unknown");
+			goto default_chipset;
+#else /* CONFIG_AMIFB_OCS */
+			panic("Unknown graphics chipset, no default driver");
+#endif /* CONFIG_AMIFB_OCS */
+			break;
+	}
 
-   aga_build_clist_hdr(clist_hdr);
+	/*
+	 * Calculate the Pixel Clock Values for this Machine
+	 */
 
-   custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr);
-   custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever);
-   custom.copjmp1 = 0;
+	pixclock[TAG_SHRES] = DIVUL(25E9, amiga_eclock);	/* SHRES:  35 ns / 28 MHz */
+	pixclock[TAG_HIRES] = DIVUL(50E9, amiga_eclock);	/* HIRES:  70 ns / 14 MHz */
+	pixclock[TAG_LORES] = DIVUL(100E9, amiga_eclock); 	/* LORES: 140 ns /  7 MHz */
 
-   /*
-    *    Enable Display DMA
-    */
+	/*
+	 * Replace the Tag Values with the Real Pixel Clock Values
+	 */
 
-   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                   DMAF_SPRITE;
+	for (i = 0; i < NUM_PREDEF_MODES; i++) {
+		tag = amiga_fb_predefined[i].pixclock;
+		if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
+			amiga_fb_predefined[i].pixclock = pixclock[tag];
+			if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag])
+				amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag];
+		}
+	}
 
-   /*
-    *    These hardware register values will never be changed later
-    */
+	err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
+	                           NUM_TOTAL_MODES, amiga_fb_predefined);
+	if (err < 0)
+		panic("Cannot register frame buffer");
+
+	chipptr = chipalloc(videomemorysize+
+	                    SPRITEMEMSIZE+
+	                    DUMMYSPRITEMEMSIZE+
+	                    COPINITSIZE+
+	                    4*COPLISTSIZE);
+
+	assignchunk(videomemory, u_long, chipptr, videomemorysize);
+	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
+	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
+	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
+	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
 
-   custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2;
-   custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
 
-   return(0);
-}
+	/*
+	 * Enable Display DMA
+	 */
 
+	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+	                DMAF_BLITTER | DMAF_SPRITE;
 
-   /*
-    *    This function should fill in the `fix' structure based on the
-    *    values in the `par' structure.
-    */
+	/*
+	 * Make sure the Copper has something to do
+	 */
 
-static int aga_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amiga_fb_par *par)
-{
-   int i;
+	ami_init_copper();
 
-   strcpy(fix->id, amiga_fb_name);
-   fix->smem_start = videomemory;
-   fix->smem_len = videomemorysize;
-
-   if (amifb_ilbm) {
-      fix->type = FB_TYPE_INTERLEAVED_PLANES;
-      fix->type_aux = par->next_line;
-   } else {
-      fix->type = FB_TYPE_PLANES;
-      fix->type_aux = 0;
-   }
-   fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
-   if (par->diwstrt_h >= 323)
-      fix->xpanstep = 1;
-   else
-      fix->xpanstep = 64;
-   fix->ypanstep = 1;
-
-   if (hw2ddfstrt(par->ddfstrt) >= (par->bpp-1)*64)
-      fix->ywrapstep = 1;
-   else
-      fix->ywrapstep = 0;
-
-   fix->line_length = 0;
-   for (i = 0; i < arraysize(fix->reserved); i++)
-      fix->reserved[i] = 0;
-
-   return(0);
-}
+	check_default_mode();
 
+	if (request_irq(IRQ3, amifb_interrupt, IRQ_FLG_LOCK,
+	                "fb vertb handler", NULL))
+		panic("Couldn't add vblank interrupt\n");
+	ami_intena_vals[IRQ_IDX(IRQ_AMIGA_VERTB)] = IF_COPER;
+	ami_intena_vals[IRQ_IDX(IRQ_AMIGA_COPPER)] = 0;
+	custom.intena = IF_VERTB;
+	custom.intena = IF_SETCLR | IF_COPER;
 
-   /*
-    *    Get the video params out of `var'. If a value doesn't fit, round
-    *    it up, if it's too big, return -EINVAL.
-    */
+	strcpy(fb_info.modename, amiga_fb_name);
+	fb_info.changevar = NULL;
+	fb_info.disp = disp;
+	fb_info.switch_con = &amifbcon_switch;
+	fb_info.updatevar = &amifbcon_updatevar;
+	fb_info.blank = &amifbcon_blank;
 
-static int aga_decode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
-{
-   u_short clk_shift, line_shift_incd;
-   u_long upper, lower, hslen, vslen;
-   int xres_n, yres_n, xoffset_n;                              /* normalized */
-   u_long left_n, right_n, upper_n, lower_n, hslen_n, vslen_n; /* normalized */
-   u_long diwstrt_h, diwstrt_v, diwstop_h, diwstop_v;
-   u_long hsstrt, vsstrt, hsstop, vsstop, htotal, vtotal;
-   u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
-   u_long hrate, vrate;
-   u_short loopcnt = 0;
-
-   /*
-    *    Find a matching Pixel Clock
-    */
-
-   for (clk_shift = 0; clk_shift < 3; clk_shift++)
-      if (var->pixclock <= pixclock[clk_shift])
-         break;
-   if (clk_shift >= 3)
-      return(-EINVAL);
-   par->clk_shift = clk_shift;
-
-   /*
-    *    Round up the Geometry Values (if necessary)
-    */
-
-   par->xres = max(var->xres, 64);
-   par->yres = max(var->yres, 64);
-   par->vxres = up64(max(var->xres_virtual, par->xres));
-   par->vyres = max(var->yres_virtual, par->yres);
-
-   par->bpp = var->bits_per_pixel;
-   if (par->bpp > 8)
-      return(-EINVAL);
-
-   if (!var->nonstd) {
-      if (par->bpp < 1)
-         par->bpp = 1;
-   } else if (var->nonstd == FB_NONSTD_HAM)
-      par->bpp = par->bpp <= 6 ? 6 : 8;
-   else
-      return(-EINVAL);
-
-   upper = var->upper_margin;
-   lower = var->lower_margin;
-   hslen = var->hsync_len;
-   vslen = var->vsync_len;
-
-   par->vmode = var->vmode;
-   switch (par->vmode & FB_VMODE_MASK) {
-      case FB_VMODE_NONINTERLACED:
-         line_shift_incd = 1;
-         break;
-      case FB_VMODE_INTERLACED:
-         line_shift_incd = 0;
-         if (par->yres & 1)
-            par->yres++;               /* even */
-         if (upper & 1)
-            upper++;                   /* even */
-         if (!(lower & 1))
-            lower++;                   /* odd */
-         if (vslen & 1)
-            vslen++;                   /* even */
-         break;
-      case FB_VMODE_DOUBLE:
-         line_shift_incd = 2;
-         break;
-      default:
-         return(-EINVAL);
-         break;
-   }
-
-   par->xoffset = var->xoffset;
-   par->yoffset = var->yoffset;
-   if (par->vmode & FB_VMODE_YWRAP) {
-      if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->yres)
-         return(-EINVAL);
-   } else {
-      if (par->xoffset < 0 || par->xoffset+par->xres > par->vxres ||
-          par->yoffset < 0 || par->yoffset+par->yres > par->vyres)
-         return(-EINVAL);
-   }
-
-   if (var->sync & FB_SYNC_BROADCAST) {
-      if (hslen || vslen)
-         return(-EINVAL);
-   } else {
-      hslen = hslen < 1 ? 1 : hslen;
-      vslen = vslen < 1 ? 1 : vslen;
-   }
-
-   /*
-    *    Check the Memory Requirements
-    */
-
-   if (par->vxres*par->vyres*par->bpp > videomemorysize<<3)
-      return(-EINVAL);
-
-   /*
-    *    Normalize all values:
-    *
-    *      - horizontal: in 35 ns (SHRES) pixels
-    *      - vertical: in non-interlaced scanlines
-    */
-
-   xres_n = par->xres<<clk_shift;
-   xoffset_n = par->xoffset<<clk_shift;
-   yres_n = par->yres<<line_shift_incd>>1;
-
-   left_n = var->left_margin<<clk_shift;
-   right_n = var->right_margin<<clk_shift;
-   hslen_n = hslen<<clk_shift;
-   upper_n = upper<<line_shift_incd>>1;
-   lower_n = lower<<line_shift_incd>>1;
-   vslen_n = vslen<<line_shift_incd>>1;
-
-   /*
-    *    Vertical and Horizontal Timings
-    */
-
-   par->bplcon3 = sprpixmode[clk_shift];
-aga_calculate_timings:
-   if (var->sync & FB_SYNC_BROADCAST) {
-      if (upper_n+yres_n+lower_n == PAL_WINDOW_V) {
-         /* PAL video mode */
-         diwstrt_v = PAL_DIWSTRT_V+upper_n;
-         diwstop_v = diwstrt_v+yres_n;
-         diwstrt_h = PAL_DIWSTRT_H+left_n;
-         diwstop_h = diwstrt_h+xres_n+1;
-         par->htotal = htotal2hw(PAL_HTOTAL);
-         hrate = 15625;
-         vrate = 50;
-         par->beamcon0 = BMC0_PAL;
-      } else if (upper_n+yres_n+lower_n == NTSC_WINDOW_V) {
-         /* NTSC video mode */
-         diwstrt_v = NTSC_DIWSTRT_V+upper_n;
-         diwstop_v = diwstrt_v+yres_n;
-         diwstrt_h = NTSC_DIWSTRT_H+left_n;
-         diwstop_h = diwstrt_h+xres_n+1;
-         par->htotal = htotal2hw(NTSC_HTOTAL);
-         hrate = 15750;
-         vrate = 60;
-         par->beamcon0 = 0;
-      } else
-         return(-EINVAL);
-   } else {
-      /* Programmable video mode */
-      vsstrt = lower_n;
-      vsstop = vsstrt+vslen_n;
-      diwstrt_v = vsstop+upper_n;
-      diwstop_v = diwstrt_v+yres_n;
-      vtotal = diwstop_v;
-      hslen_n = up8(hslen_n);
-      htotal = up8(left_n+xres_n+right_n+hslen_n);
-      if (vtotal > 2048 || htotal > 2048)
-         return(-EINVAL);
-      right_n = htotal-left_n-xres_n-hslen_n;
-      hsstrt = down8(right_n+4);
-      hsstop = hsstrt+hslen_n;
-      diwstop_h = htotal+hsstrt-right_n+1;
-      diwstrt_h = diwstop_h-xres_n-1;
-      hrate = (amiga_masterclock+htotal/2)/htotal;
-      vrate = (amiga_masterclock+htotal*vtotal/2)/(htotal*vtotal);
-      par->bplcon3 |= BPC3_BRDRBLNK | BPC3_EXTBLKEN;
-      par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
-                      BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
-                      BMC0_PAL | BMC0_VARCSYEN;
-      if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-         par->beamcon0 |= BMC0_HSYTRUE;
-      if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-         par->beamcon0 |= BMC0_VSYTRUE;
-      if (var->sync & FB_SYNC_COMP_HIGH_ACT)
-         par->beamcon0 |= BMC0_CSYTRUE;
-      par->htotal = htotal2hw(htotal);
-      par->hsstrt = hsstrt2hw(hsstrt);
-      par->hsstop = hsstop2hw(hsstop);
-      par->vtotal = vtotal2hw(vtotal);
-      par->vsstrt = vsstrt2hw(vsstrt);
-      par->vsstop = vsstop2hw(vsstop);
-      par->hcenter = par->hsstrt+(par->htotal>>1);
-   }
-   par->diwstrt_v = diwstrt_v;
-   par->diwstrt_h = diwstrt_h;
-   par->crsr_x = 0;
-   par->crsr_y = 0;
-
-   /*
-    *    DMA Timings
-    */
-
-   ddfmin = down64(xoffset_n);
-   ddfmax = up64(xoffset_n+xres_n);
-   hscroll = diwstrt_h-68-mod64(xoffset_n);
-   ddfstrt = down64(hscroll);
-   if (ddfstrt < 128) {
-      right_n += (128-hscroll);
-      /* Prevent an infinite loop */
-      if (loopcnt++)
-         return(-EINVAL);
-      goto aga_calculate_timings;
-   }
-   hscroll -= ddfstrt;
-   ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
-
-   /*
-    *    Bitplane calculations
-    */
-
-   if (amifb_ilbm) {
-      par->next_plane = div8(par->vxres);
-      par->next_line = par->bpp*par->next_plane;
-   } else {
-      par->next_line = div8(par->vxres);
-      par->next_plane = par->vyres*par->next_line;
-   }
-   par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
-                            par->yoffset*par->next_line);
-   par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
-   par->bpl2mod = par->bpl1mod;
-
-   /*
-    *    Hardware Register Values
-    */
-
-   par->bplcon0 = BPC0_COLOR | BPC0_ECSENA | bplpixmode[clk_shift];
-   if (par->bpp == 8)
-      par->bplcon0 |= BPC0_BPU3;
-   else
-      par->bplcon0 |= par->bpp<<12;
-   if (var->nonstd == FB_NONSTD_HAM)
-      par->bplcon0 |= BPC0_HAM;
-   if (var->sync & FB_SYNC_EXT)
-      par->bplcon0 |= BPC0_ERSY;
-   par->bplcon1 = hscroll2hw(hscroll);
-   par->diwstrt = diwstrt2hw(diwstrt_h, diwstrt_v);
-   par->diwstop = diwstop2hw(diwstop_h, diwstop_v);
-   par->diwhigh = diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v);
-   par->ddfstrt = ddfstrt2hw(ddfstrt);
-   par->ddfstop = ddfstop2hw(ddfstop);
-   par->fmode = FMODE_SPAGEM | FMODE_SPR32 | FMODE_BPAGEM | FMODE_BPL32;
-
-   switch (par->vmode & FB_VMODE_MASK) {
-      case FB_VMODE_INTERLACED:
-         par->bpl1mod += par->next_line;
-         par->bpl2mod += par->next_line;
-         par->bplcon0 |= BPC0_LACE;
-         break;
-      case FB_VMODE_DOUBLE:
-         par->bpl1mod -= par->next_line;
-         par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
-         break;
-   }
-
-   if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
-      return(-EINVAL);
-
-   return(0);
-}
-
-
-   /*
-    *    Fill the `var' structure based on the values in `par' and maybe
-    *    other values read out of the hardware.
-    */
+	amiga_fb_set_var(&amiga_fb_predefined[0], 0);
 
-static int aga_encode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
-{
-   u_short clk_shift, line_shift_incd;
-   u_long left, right, upper, lower, hslen, vslen;
-   u_short diwstop_h, diwstop_v;
-   u_short hsstrt, vsstrt, hsstop, vsstop, htotal;
-   int i;
-
-   var->xres = par->xres;
-   var->yres = par->yres;
-   var->xres_virtual = par->vxres;
-   var->yres_virtual = par->vyres;
-   var->xoffset = par->xoffset;
-   var->yoffset = par->yoffset;
-
-   var->bits_per_pixel = par->bpp;
-   var->grayscale = 0;
-
-   var->red.offset = 0;
-   var->red.length = 8;
-   var->red.msb_right = 0;
-   var->blue = var->green = var->red;
-   var->transp.offset = 0;
-   var->transp.length = 0;
-   var->transp.msb_right = 0;
-
-   if (par->bplcon0 & BPC0_HAM)
-      var->nonstd = FB_NONSTD_HAM;
-   else
-      var->nonstd = 0;
-   var->activate = 0;
-
-   var->height = -1;
-   var->width = -1;
-   var->accel = FB_ACCEL_NONE;
-
-   clk_shift = par->clk_shift;
-   var->pixclock = pixclock[clk_shift];
-
-   diwstop_h = hw2diwstop_h(par->diwstop, par->diwhigh);
-   if (par->beamcon0 & BMC0_VARBEAMEN) {
-      hsstrt = hw2hsstrt(par->hsstrt);
-      vsstrt = hw2vsstrt(par->vsstrt);
-      hsstop = hw2hsstop(par->hsstop);
-      vsstop = hw2vsstop(par->vsstop);
-      htotal = hw2htotal(par->htotal);
-      left = par->diwstrt_h-hsstop;
-      right = htotal+hsstrt-diwstop_h+1;
-      hslen = hsstop-hsstrt;
-      upper = par->diwstrt_v-vsstop;
-      lower = vsstrt;
-      vslen = vsstop-vsstrt;
-      var->sync = 0;
-   } else {
-      diwstop_v = hw2diwstop_v(par->diwstop, par->diwhigh);
-      if (par->beamcon0 & BMC0_PAL) {
-         left = par->diwstrt_h-PAL_DIWSTRT_H;
-         right = PAL_DIWSTRT_H+PAL_WINDOW_H-diwstop_h+1;
-         upper = par->diwstrt_v-PAL_DIWSTRT_V;
-         lower = PAL_DIWSTRT_V+PAL_WINDOW_V-diwstop_v;
-      } else {
-         left = par->diwstrt_h-NTSC_DIWSTRT_H;
-         right = NTSC_DIWSTRT_H+NTSC_WINDOW_H-diwstop_h;
-         upper = par->diwstrt_v-NTSC_DIWSTRT_V;
-         lower = NTSC_DIWSTRT_V+NTSC_WINDOW_V-diwstop_v;
-      }
-      hslen = 0;
-      vslen = 0;
-      var->sync = FB_SYNC_BROADCAST;
-   }
-
-   if (par->bplcon0 & BPC0_ERSY)
-      var->sync |= FB_SYNC_EXT;
-   if (par->beamcon0 & BMC0_HSYTRUE)
-      var->sync |= FB_SYNC_HOR_HIGH_ACT;
-   if (par->beamcon0 & BMC0_VSYTRUE)
-      var->sync |= FB_SYNC_VERT_HIGH_ACT;
-   if (par->beamcon0 & BMC0_CSYTRUE)
-      var->sync |= FB_SYNC_COMP_HIGH_ACT;
-
-   switch (par->vmode & FB_VMODE_MASK) {
-      case FB_VMODE_NONINTERLACED:
-         line_shift_incd = 1;
-         break;
-      case FB_VMODE_INTERLACED:
-         line_shift_incd = 0;
-         break;
-      case FB_VMODE_DOUBLE:
-         line_shift_incd = 2;
-         break;
-   }
-
-   var->left_margin = left>>clk_shift;
-   var->right_margin = right>>clk_shift;
-   var->upper_margin = upper<<1>>line_shift_incd;
-   var->lower_margin = lower<<1>>line_shift_incd;
-   var->hsync_len = hslen>>clk_shift;
-   var->vsync_len = vslen<<1>>line_shift_incd;
-   var->vmode = par->vmode;
-   for (i = 0; i < arraysize(var->reserved); i++)
-      var->reserved[i] = 0;
-
-   return(0);
-}
-
-
-   /*
-    *    Read a single color register and split it into
-    *    colors/transparent. Return != 0 for invalid regno.
-    */
+	return &fb_info;
+}
 
-static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp)
+static int amifbcon_switch(int con)
 {
-   if (regno > 255)
-      return(1);
+	/* Do we have to save the colormap? */
+	if (disp[currcon].cmap.len)
+		do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
 
-   *red = palette[regno].red;
-   *green = palette[regno].green;
-   *blue = palette[regno].blue;
-   return(0);
+	currcon = con;
+	ami_set_var(&disp[con].var);
+	/* Install new colormap */
+	do_install_cmap(con);
+	return 0;
 }
 
+	/*
+	 * Update the `var' structure (called by amicon.c)
+	 */
 
-   /*
-    *    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 aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp)
+static int amifbcon_updatevar(int con)
 {
-   u_short bplcon3 = current_par.bplcon3;
-
-   if (regno > 255)
-      return(1);
+	ami_pan_var(&disp[con].var);
+	return 0;
+}
 
-   /*
-    *    Update the corresponding Hardware Color Register, unless it's Color
-    *    Register 0 and the screen is blanked.
-    *
-    *    The cli()/sti() pair is here to protect bplcon3 from being changed by
-    *    the VBlank interrupt routine.
-    */
-
-   cli();
-   if (regno || !is_blanked) {
-      custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
-      custom.color[regno&31] = rgb2hw_high(red, green, blue);
-      custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
-      custom.color[regno&31] = rgb2hw_low(red, green, blue);
-      custom.bplcon3 = bplcon3;
-   }
-   sti();
-
-   palette[regno].red = red;
-   palette[regno].green = green;
-   palette[regno].blue = blue;
-
-   return(0);
-}
-
-
-   /*
-    *    Pan or Wrap the Display
-    *
-    *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-    *    in `var'.
-    */
-
-static int aga_pan_display(struct fb_var_screeninfo *var,
-                           struct amiga_fb_par *par)
-{
-   int xoffset, yoffset, vmode, xres_n, xoffset_n;
-   u_short clk_shift, line_shift_incd;
-   u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
-
-   xoffset = var->xoffset;
-   yoffset = var->yoffset;
-   if (var->vmode & FB_VMODE_YWRAP) {
-      if (hw2ddfstrt(par->ddfstrt) < (par->bpp-1)*64 || xoffset ||
-          yoffset < 0 || yoffset >= par->yres)
-         return(-EINVAL);
-      vmode = par->vmode | FB_VMODE_YWRAP;
-   } else {
-      if (par->diwstrt_h < 323)
-         xoffset = up64(xoffset);
-      if (xoffset < 0 || xoffset+par->xres > par->vxres ||
-          yoffset < 0 || yoffset+par->yres > par->vyres)
-         return(-EINVAL);
-      vmode = par->vmode & ~FB_VMODE_YWRAP;
-   }
-
-   clk_shift = par->clk_shift;
-   switch (vmode & FB_VMODE_MASK) {
-      case FB_VMODE_NONINTERLACED:
-         line_shift_incd = 1;
-         break;
-      case FB_VMODE_INTERLACED:
-         line_shift_incd = 0;
-         break;
-      case FB_VMODE_DOUBLE:
-         line_shift_incd = 2;
-         break;
-   }
-   xres_n = par->xres<<clk_shift;
-   xoffset_n = xoffset<<clk_shift;
-
-   /*
-    *    DMA timings
-    */
-
-   ddfmin = down64(xoffset_n);
-   ddfmax = up64(xoffset_n+xres_n);
-   hscroll = par->diwstrt_h-68-mod64(xoffset_n);
-   ddfstrt = down64(hscroll);
-   if (ddfstrt < 128)
-      return(-EINVAL);
-   hscroll -= ddfstrt;
-   ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
-   par->bplcon1 = hscroll2hw(hscroll);
-   par->ddfstrt = ddfstrt2hw(ddfstrt);
-   par->ddfstop = ddfstop2hw(ddfstop);
-
-   /*
-    *    Bitplane calculations
-    */
-
-   par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
-                            yoffset*par->next_line);
-   par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
-   par->bpl2mod = par->bpl1mod;
-   switch (vmode & FB_VMODE_MASK) {
-      case FB_VMODE_INTERLACED:
-         par->bpl1mod += par->next_line;
-         par->bpl2mod += par->next_line;
-         break;
-      case FB_VMODE_DOUBLE:
-         par->bpl1mod -= par->next_line;
-         break;
-   }
-
-   par->xoffset = var->xoffset = xoffset;
-   par->yoffset = var->yoffset = yoffset;
-   par->vmode = var->vmode = vmode;
-   return(0);
-}
-
-
-   /*
-    *    Change the video mode (called by VBlank interrupt)
-    */
-
-void aga_do_vmode(void)
-{
-   struct amiga_fb_par *par = &current_par;
-
-   /*
-    *    Rebuild the dynamic part of the Copper List and activate the right
-    *    Copper List as soon as possible
-    *
-    *    Make sure we're in a Long Frame if the video mode is interlaced.
-    *    This is always the case if we already were in an interlaced mode,
-    *    since then the VBlank only calls us during a Long Frame.
-    *    But this _is_ necessary if we're switching from a non-interlaced
-    *    to an interlaced mode.
-    */
-
-   if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-      custom.vposw = 0x8000;
-      aga_build_clist_dyn(clist_lof, clist_shf, 0, par);
-      custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
-      aga_build_clist_dyn(clist_shf, clist_lof, 1, par);
-   } else {
-      aga_build_clist_dyn(clist_lof, NULL, 0, par);
-      custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
-   }
-
-   /*
-    *    Update the hardware registers
-    */
-
-   if (full_vmode_change) {
-      custom.fmode = par->fmode;
-      custom.beamcon0 = par->beamcon0;
-      if (par->beamcon0 & BMC0_VARBEAMEN) {
-         custom.htotal = par->htotal;
-         custom.vtotal = par->vtotal;
-         custom.hsstrt = par->hsstrt;
-         custom.hsstop = par->hsstop;
-         custom.hbstrt = par->hsstrt;
-         custom.hbstop = par->hsstop;
-         custom.vsstrt = par->vsstrt;
-         custom.vsstop = par->vsstop;
-         custom.vbstrt = par->vsstrt;
-         custom.vbstop = par->vsstop;
-         custom.hcenter = par->hcenter;
-      }
-      custom.bplcon3 = par->bplcon3;
-      full_vmode_change = 0;
-
-      /*
-       *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-       */
-
-      if (boot_info.bi_amiga.chipset != CS_STONEAGE)
-         amiga_audio_min_period = (par->htotal>>1)+1;
-   }
-   custom.ddfstrt = par->ddfstrt;
-   custom.ddfstop = par->ddfstop;
-   custom.bpl1mod = par->bpl1mod;
-   custom.bpl2mod = par->bpl2mod;
-   custom.bplcon1 = par->bplcon1;
-
-   /*
-    *    Update the Frame Header Copper List
-    */
-
-   aga_update_clist_hdr(clist_hdr, par);
-}
-
-
-   /*
-    *    (Un)Blank the screen (called by VBlank interrupt)
-    */
-
-void aga_do_blank(int blank)
-{
-   struct amiga_fb_par *par = &current_par;
-   u_short bplcon3 = par->bplcon3;
-   u_char red, green, blue;
-
-   if (blank) {
-      custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
-      red = green = blue = 0;
-      if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
-         /* VESA suspend mode, switch off HSYNC */
-         custom.hsstrt = par->htotal+2;
-         custom.hsstop = par->htotal+2;
-      }
-   } else {
-      custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
-      red = palette[0].red;
-      green = palette[0].green;
-      blue = palette[0].blue;
-      if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
-         custom.hsstrt = par->hsstrt;
-         custom.hsstop = par->hsstop;
-      }
-   }
-   custom.bplcon3 = bplcon3;
-   custom.color[0] = rgb2hw_high(red, green, blue);
-   custom.bplcon3 = bplcon3 | BPC3_LOCT;
-   custom.color[0] = rgb2hw_low(red, green, blue);
-   custom.bplcon3 = bplcon3;
-
-   is_blanked = blank;
-}
-
-
-   /*
-    *    Move the cursor (called by VBlank interrupt)
-    */
-
-void aga_do_movecursor(void)
-{
-   struct amiga_fb_par *par = &current_par;
-   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
-   long hs, vs, ve;
-   u_short s1, s2, is_double = 0;
-
-   if (par->crsr_x <= -64 || par->crsr_x >= par->xres || par->crsr_y <= -64 ||
-       par->crsr_y >= par->yres)
-      hs = vs = ve = 0;
-   else {
-      hs = par->diwstrt_h-4+(par->crsr_x<<par->clk_shift);
-      vs = par->crsr_y;
-      ve = min(vs+64, par->yres);
-      switch (par->vmode & FB_VMODE_MASK) {
-         case FB_VMODE_INTERLACED:
-            vs >>= 1;
-            ve >>= 1;
-            break;
-         case FB_VMODE_DOUBLE:
-            vs <<= 1;
-            ve <<= 1;
-            is_double = 1;
-            break;
-      }
-      vs += par->diwstrt_v;
-      ve += par->diwstrt_v;
-   }
-   s1 = spr2hw_pos(vs, hs);
-   if (is_double)
-      s1 |= 0x80;
-   s2 = spr2hw_ctl(vs, hs, ve);
-   sprite->sprpos = s1;
-   sprite->sprctl = s2;
-
-   /*
-    *    TODO: Special cases:
-    *    
-    *      - Interlaced: fill position in in both lofsprite & shfsprite
-    *                    swap lofsprite & shfsprite on odd lines
-    *    
-    *      - Doublescan: OK?
-    *    
-    *      - ve <= bottom of display: OK?
-    */
-}
-
-
-   /*
-    *    Flash the cursor (called by VBlank interrupt)
-    */
+	/*
+	 * Blank the display.
+	 */
 
-void aga_do_flashcursor(void)
+static void amifbcon_blank(int blank)
 {
-#if 1
-   static int cursorcount = 0;
-   static int cursorstate = 0;
-
-   switch (cursormode) {
-      case FB_CURSOR_OFF:
-         custom.dmacon = DMAF_SPRITE;
-         break;
-      case FB_CURSOR_ON:
-         custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
-         break;
-      case FB_CURSOR_FLASH:
-         if (cursorcount)
-            cursorcount--;
-         else {
-            cursorcount = CRSR_RATE;
-            if ((cursorstate = !cursorstate))
-               custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
-            else
-               custom.dmacon = DMAF_SPRITE;
-         }
-         break;
-   }
-#endif
+	do_blank = blank ? blank : -1;
 }
 
+/* ---------------------------- Generic routines ---------------------------- */
 
-#if 1
-static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static struct fb_cmap *get_default_colormap(int bpp)
 {
-#if 0
-   if (ddfstrt >= 192) {
-#endif
-      fix->crsr_width = 64;
-      fix->crsr_height = 64;
-      fix->crsr_xsize = 64;
-      fix->crsr_ysize = 64;
-      fix->crsr_color1 = 17;
-      fix->crsr_color2 = 18;
-#if 0
-   } else {
-      fix->crsr_width = 0;
-      fix->crsr_height = 0;
-      fix->crsr_xsize = 0;
-      fix->crsr_ysize = 0;
-      fix->crsr_color1 = 0;
-      fix->crsr_color2 = 0;
-   }
-#endif
-   return(0);
+	switch (bpp) {
+		case 1:
+			return &default_2_colors;
+			break;
+		case 2:
+			return &default_4_colors;
+			break;
+		case 3:
+			return &default_8_colors;
+			break;
+		default:
+			return &default_16_colors;
+			break;
+	}
 }
 
+#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 aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc)
 {
-   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+	int i, start;
+	u_short *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp;
 
-   /* TODO: interlaced sprites */
-   memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data));
-   return(0);
+	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 (ami_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_fs_word(hred, red);
+			put_fs_word(hgreen, green);
+			put_fs_word(hblue, blue);
+			if (transp)
+				put_fs_word(htransp, transp);
+		}
+		red++;
+		green++;
+		blue++;
+		if (transp)
+			transp++;
+	}
+	return 0;
 }
 
-
-static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc)
 {
-   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+	int i, start;
+	u_short *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp;
 
-   /* TODO: interlaced sprites */
-   memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data));
-   return(0);
-}
+	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 {
+			hred = get_fs_word(red);
+			hgreen = get_fs_word(green);
+			hblue = get_fs_word(blue);
+			htransp = transp ? get_fs_word(transp) : 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 (ami_setcolreg(start++, hred, hgreen, hblue, htransp))
+			return 0;
+	}
+	return 0;
+}
 
-static int aga_get_cursorstate(struct fb_cursorstate *state, int con)
+static void do_install_cmap(int con)
 {
-   state->xoffset = current_par.crsr_x;
-   state->yoffset = current_par.crsr_y;
-   state->mode = cursormode;
-   return(0);
+	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 int aga_set_cursorstate(struct fb_cursorstate *state, int con)
+static void memcpy_fs(int fsfromto, void *to, void *from, int len)
 {
-   current_par.crsr_x = state->xoffset;
-   current_par.crsr_y = state->yoffset;
-   cursormode = state->mode;
-   do_movecursor = 1;
-   return(0);
+	switch (fsfromto) {
+		case 0:
+			memcpy(to, from, len);
+			return;
+		case 1:
+			memcpy_fromfs(to, from, len);
+			return;
+		case 2:
+			memcpy_tofs(to, from, len);
+			return;
+	}
 }
-#endif
 
+static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+{
+	int size;
+	int tooff = 0, fromoff = 0;
 
-   /*
-    *    Build the Frame Header Copper List
-    */
-
-static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop)
-{
-   int i, j;
-   u_long p;
-
-   cop->bplcon0.l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
-   cop->diwstrt.l = CMOVE(0x0181, diwstrt);
-   cop->diwstop.l = CMOVE(0x0281, diwstop);
-   cop->diwhigh.l = CMOVE(0x0000, diwhigh);
-   for (i = 0; i < 8; i++)
-      cop->sprfix[i].l = CMOVE(0, spr[i].pos);
-   for (i = 0, j = 0; i < 8; i++) {
-      p = ZTWO_PADDR(dummysprite);
-      cop->sprstrtup[j++].l = CMOVE(highw(p), sprpt[i]);
-      cop->sprstrtup[j++].l = CMOVE2(loww(p), sprpt[i]);
-   }
-   cop->wait.l = CWAIT(0, 12);         /* Initial value */
-   cop->jump.l = CMOVE(0, copjmp2);
-   cop->wait_forever.l = CEND;
-}
-
-
-   /*
-    *    Update the Frame Header Copper List
-    */
-
-static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
-                                            struct amiga_fb_par *par)
-{
-   cop->bplcon0.l = CMOVE(~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) &
-                          par->bplcon0, bplcon0);
-   cop->wait.l = CWAIT(0, par->diwstrt_v-2);
-}
-
-
-   /*
-    *    Build the Long Frame/Short Frame Copper List
-    */
-
-static void aga_build_clist_dyn(struct clist_dyn *cop,
-                                struct clist_dyn *othercop, u_short shf,
-                                struct amiga_fb_par *par)
-{
-   u_long y_wrap, bplpt0, p, line;
-   int i, j = 0;
-
-   cop->diwstrt.l = CMOVE(par->diwstrt, diwstrt);
-   cop->diwstop.l = CMOVE(par->diwstop, diwstop);
-   cop->diwhigh.l = CMOVE(par->diwhigh, diwhigh);
-   cop->bplcon0.l = CMOVE(par->bplcon0, bplcon0);
-
-   /* Point Sprite 0 at cursor sprite */
-
-   /* TODO: This should depend on the vertical sprite position too */
-   if (shf) {
-      p = ZTWO_PADDR(shfsprite);
-      cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
-      cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
-   } else {
-      p = ZTWO_PADDR(lofsprite);
-      cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
-      cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
-   }
-
-   bplpt0 = par->bplpt0;
-   if (shf)
-      bplpt0 += par->next_line;
-   y_wrap = par->vmode & FB_VMODE_YWRAP ? par->yoffset : 0;
-
-   /* Set up initial bitplane ptrs */
-
-   for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
-      cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
-      cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
-   }
-
-   if (y_wrap) {
-      bplpt0 -= y_wrap*par->next_line;
-      line = par->yres-y_wrap;
-      switch (par->vmode & FB_VMODE_MASK) {
-         case FB_VMODE_INTERLACED:
-            line >>= 1;
-            break;
-         case FB_VMODE_DOUBLE:
-            line <<= 1;
-            break;
-      }
-      line += par->diwstrt_v;
-
-      /* Handle skipping over 256-line chunks */
-
-      while (line > 256) {
-         /* Hardware limitation - 8 bit counter */
-         cop->rest[j++].l = CWAIT(par->htotal-4, 255);
-         /* Wait(0, 0) - make sure we're in the new segment */
-         cop->rest[j++].l = CWAIT(0, 0);
-         line -= 256;
-      }
-      cop->rest[j++].l = CWAIT(par->htotal-11, line-1);
-
-      for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
-         cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
-         cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
-      }
-   }
-
-   if (othercop) {
-      p = ZTWO_PADDR(othercop);
-      cop->rest[j++].l = CMOVE(highw(p), cop2lc);
-      cop->rest[j++].l = CMOVE2(loww(p), cop2lc);
-   }
+	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(u_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);
+}
 
-   /* End of Copper list */
-   cop->rest[j++].l = CEND;
+static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+	int size = len*sizeof(u_short);
 
-   if (j > arraysize(cop->rest))
-      printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j);
+	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;
 }
-#endif /* CONFIG_AMIFB_AGA */
 
+static int flash_cursor(void)
+{
+	static int cursorcount = 1;
 
-/* -------------------- Interfaces to hardware functions -------------------- */
+	if (cursormode == FB_CURSOR_FLASH) {
+		if (!--cursorcount) {
+			cursorstate = -cursorstate;
+			cursorcount = cursorrate;
+			if (!is_blanked)
+				return 1;
+		}
+	}
+	return 0;
+}
 
+	/*
+	 * VBlank Display Interrupt
+	 */
 
-#ifdef CONFIG_AMIFB_OCS
-static struct fb_hwswitch ocs_switch = {
-   ocs_init, ocs_encode_fix, ocs_decode_var, ocs_encode_var, ocs_getcolreg,
-   ocs_setcolreg, ocs_pan_display, ocs_do_vmode, ocs_do_blank,
-   ocs_do_movecursor, ocs_do_flashcursor
-};
-#endif /* CONFIG_AMIFB_OCS */
+static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	u_short ints = custom.intreqr & custom.intenar;
+	static struct irq_server server = {0, 0};
 
-#ifdef CONFIG_AMIFB_ECS
-static struct fb_hwswitch ecs_switch = {
-   ecs_init, ecs_encode_fix, ecs_decode_var, ecs_encode_var, ecs_getcolreg,
-   ecs_setcolreg, ecs_pan_display, ecs_do_vmode, ecs_do_blank,
-   ecs_do_movecursor, ecs_do_flashcursor
-};
-#endif /* CONFIG_AMIFB_ECS */
+	if (ints & IF_BLIT) {
+		custom.intreq = IF_BLIT;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp);
+	}
+
+	if (ints & IF_COPER) {
+		custom.intreq = IF_COPER;
+		if (do_vmode_pan || do_vmode_full)
+			ami_update_display();
+
+		if (do_vmode_full)
+			ami_init_display();
+
+		if (do_vmode_pan) {
+			flash_cursor();
+			ami_rebuild_copper();
+			do_cursor = do_vmode_pan = 0;
+		} else if (do_cursor) {
+			flash_cursor();
+			ami_set_sprite();
+			do_cursor = 0;
+		} else {
+			if (flash_cursor())
+				ami_set_sprite();
+		}
 
-#ifdef CONFIG_AMIFB_AGA
-static struct fb_hwswitch aga_switch = {
-   aga_init, aga_encode_fix, aga_decode_var, aga_encode_var, aga_getcolreg,
-   aga_setcolreg, aga_pan_display, aga_do_vmode, aga_do_blank,
-   aga_do_movecursor, aga_do_flashcursor
-};
-#endif /* CONFIG_AMIFB_AGA */
+		if (get_vbpos() < down2(currentpar.diwstrt_v - 4))
+			custom.copjmp2 = 0;
 
+		if (do_blank) {
+			ami_do_blank();
+			do_blank = 0;
+		}
 
-/* -------------------- Generic routines ------------------------------------ */
+		if (do_vmode_full) {
+			ami_reinit_copper();
+			do_vmode_full = 0;
+		}
+		amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server);
+	}
 
+	if (ints & IF_VERTB) {
+		printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
+		custom.intena = IF_VERTB;
+	}
+}
 
-   /*
-    *    Allocate, Clear and Align a Block of Chip Memory
-    */
+	/*
+	 * Get a Video Modes
+	 */
 
-static u_long chipalloc(u_long size)
+static void get_video_mode(const char *name)
 {
-   u_long ptr;
-
-   size += PAGE_SIZE-1;
-   if (!(ptr = (u_long)amiga_chip_alloc(size)))
-      panic("No Chip RAM for frame buffer");
-   memset((void *)ptr, 0, size);
-   ptr = PAGE_ALIGN(ptr);
+	int i;
 
-   return(ptr);
+	for (i = 1; i < NUM_PREDEF_MODES; i++) {
+		if (!strcmp(name, amiga_fb_modenames[i])) {
+			amiga_fb_predefined[0] = amiga_fb_predefined[i];
+			amifb_usermode = i;
+			return;
+		}
+	}
 }
 
+	/*
+	 * Probe the  Video Modes
+	 */
 
-   /*
-    *    Fill the hardware's `par' structure.
-    */
-
-static void amiga_fb_get_par(struct amiga_fb_par *par)
+static void check_default_mode(void)
 {
-   if (current_par_valid)
-      *par = current_par;
-   else
-      fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par);
+	struct amiga_fb_par par;
+	int mode;
+
+	for (mode = 0; mode < NUM_PREDEF_MODES; mode++) {
+		if (!ami_decode_var(&amiga_fb_predefined[mode], &par)) {
+			if (mode)
+				amiga_fb_predefined[0] = amiga_fb_predefined[mode];
+			return;
+		}
+		if (!mode)
+			printk("Can't use default video mode. Probing video modes...\n");
+	}
+	panic("Can't find any usable video mode");
 }
 
+	/*
+	 * Allocate, Clear and Align a Block of Chip Memory
+	 */
 
-static void amiga_fb_set_par(struct amiga_fb_par *par)
+static u_long chipalloc(u_long size)
 {
-   do_vmode = 0;
-   current_par = *par;
-   full_vmode_change = 1;
-   do_vmode = 1;
-   current_par_valid = 1;
+	u_long ptr;
+
+	size += PAGE_SIZE-1;
+	if (!(ptr = (u_long)amiga_chip_alloc(size)))
+		panic("No Chip RAM for frame buffer");
+	memset((void *)ptr, 0, size);
+	ptr = PAGE_ALIGN(ptr);
+
+	return ptr;
 }
 
+	/*
+	 * A strtok which returns empty strings, too
+	 */
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static char *strtoke(char *s,const char *ct)
 {
-   int err, activate;
-   struct amiga_fb_par par;
+	char *sbegin, *send;
+	static char *ssave = NULL;
 
-   if ((err = fbhw->decode_var(var, &par)))
-      return(err);
-   activate = var->activate;
-   if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-      amiga_fb_set_par(&par);
-   fbhw->encode_var(var, &par);
-   var->activate = activate;
-   return(0);
+	sbegin  = s ? s : ssave;
+	if (!sbegin)
+		return NULL;
+	if (*sbegin == '\0') {
+		ssave = NULL;
+		return NULL;
+	}
+	send = strpbrk(sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	ssave = send;
+	return sbegin;
 }
 
+/* --------------------------- Hardware routines --------------------------- */
 
-   /*
-    *    Default Colormaps
-    */
-
-static u_short red2[] =
-   { 0x0000, 0xc000 };
-static u_short green2[] =
-   { 0x0000, 0xc000 };
-static u_short blue2[] =
-   { 0x0000, 0xc000 };
+	/*
+	 * This function should fill in the `fix' structure based on the
+	 * values in the `par' structure.
+	 */
 
-static u_short red4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short green4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short blue4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
+static int ami_encode_fix(struct fb_fix_screeninfo *fix,
+                          struct amiga_fb_par *par)
+{
+	int i;
 
-static u_short red8[] =
-   { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
-static u_short green8[] =
-   { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
-static u_short blue8[] =
-   { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
+	strcpy(fix->id, amiga_fb_name);
+	fix->smem_start = videomemory;
+	fix->smem_len = videomemorysize;
+
+	if (amifb_ilbm) {
+		fix->type = FB_TYPE_INTERLEAVED_PLANES;
+		fix->type_aux = par->next_line;
+	} else {
+		fix->type = FB_TYPE_PLANES;
+		fix->type_aux = 0;
+	}
+	fix->line_length = div8(upx(16<<maxfmode, par->vxres));
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
 
-static u_short red16[] =
-   { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
-     0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static u_short green16[] =
-   { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
-     0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static u_short blue16[] =
-   { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
-     0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
+	if (par->vmode & FB_VMODE_YWRAP) {
+		fix->ywrapstep = 1;
+		fix->xpanstep = fix->ypanstep = 0;
+	} else {
+		fix->ywrapstep = 0;
+		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
+			fix->xpanstep = 1;
+		else
+			fix->xpanstep = 16<<maxfmode;
+		fix->ypanstep = 1;
+	}
 
+	for (i = 0; i < arraysize(fix->reserved); i++)
+		fix->reserved[i] = 0;
 
-static struct fb_cmap default_2_colors =
-   { 0, 2, red2, green2, blue2, NULL };
-static struct fb_cmap default_8_colors =
-   { 0, 8, red8, green8, blue8, NULL };
-static struct fb_cmap default_4_colors =
-   { 0, 4, red4, green4, blue4, NULL };
-static struct fb_cmap default_16_colors =
-   { 0, 16, red16, green16, blue16, NULL };
+	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 struct fb_cmap *get_default_colormap(int bpp)
+static int ami_decode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par)
 {
-   switch (bpp) {
-      case 1:
-         return(&default_2_colors);
-         break;
-      case 2:
-         return(&default_4_colors);
-         break;
-      case 3:
-         return(&default_8_colors);
-         break;
-      default:
-         return(&default_16_colors);
-         break;
-   }
-}
+	u_short clk_shift, line_shift;
+	u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
+	u_long hrate = 0, vrate = 0;
 
+	/*
+	 * Find a matching Pixel Clock
+	 */
 
-#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
-                                              ((1<<(width))-1)) : 0))
+	for (clk_shift = TAG_SHRES; clk_shift < TAG_LORES; clk_shift++)
+		if (var->pixclock <= pixclock[clk_shift])
+			break;
+	if (clk_shift >= TAG_LORES)
+		return -EINVAL;
+	par->clk_shift = clk_shift;
 
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-   int i, start;
-   u_short *red, *green, *blue, *transp;
-   u_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_fs_word(hred, red);
-         put_fs_word(hgreen, green);
-         put_fs_word(hblue, blue);
-         if (transp)
-            put_fs_word(htransp, transp);
-      }
-      red++;
-      green++;
-      blue++;
-      if (transp)
-         transp++;
-   }
-   return(0);
-}
+	/*
+	 * Check the Geometry Values
+	 */
 
+	if ((par->xres = var->xres) < 64)
+		return -EINVAL;
+	if ((par->yres = var->yres) < 64)
+		return -EINVAL;
+	if ((par->vxres = var->xres_virtual) < 64)
+		return -EINVAL;
+	if ((par->vyres = var->yres_virtual) < 64)
+		return -EINVAL;
+
+	par->bpp = var->bits_per_pixel;
+	if (!var->nonstd) {
+		if (par->bpp <= 0 || par->bpp > maxdepth[clk_shift])
+			return -EINVAL;
+	} else if (var->nonstd == FB_NONSTD_HAM) {
+		if (par->bpp != 6)
+			if (par->bpp != 8 || !IS_AGA)
+				return -EINVAL;
+	} else
+		return -EINVAL;
 
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-   int i, start;
-   u_short *red, *green, *blue, *transp;
-   u_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 {
-         hred = get_fs_word(red);
-         hgreen = get_fs_word(green);
-         hblue = get_fs_word(blue);
-         htransp = transp ? get_fs_word(transp) : 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);
-}
+	/*
+	 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
+	 * checks failed and smooth scrolling is not possible
+	 */
+
+	par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
+	switch (par->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_INTERLACED:
+			line_shift = 0;
+			break;
+		case FB_VMODE_NONINTERLACED:
+			line_shift = 1;
+			break;
+		case FB_VMODE_DOUBLE:
+			if (!IS_AGA)
+				return -EINVAL;
+			line_shift = 2;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	par->line_shift = line_shift;
+
+	/*
+	 * Vertical and Horizontal Timings
+	 */
 
+	xres_n = par->xres<<clk_shift;
+	yres_n = par->yres<<line_shift;
+	par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
+	par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
+
+	if (IS_AGA)
+		par->bplcon3 = sprpixmode[clk_shift];
+	else
+		par->bplcon3 = 0;
+	if (var->sync & FB_SYNC_BROADCAST) {
+		par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
+		if (IS_AGA)
+			par->diwstop_h += mod4(var->hsync_len);
+		else
+			par->diwstop_h = down4(par->diwstop_h);
+		par->diwstrt_h = par->diwstop_h - xres_n;
+		par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
+		par->diwstrt_v = par->diwstop_v - yres_n;
+		if (par->diwstop_h >= par->htotal+8 || par->diwstop_v > par->vtotal)
+			return -EINVAL;
+		if (!IS_OCS) {
+			/* Initialize sync with some reasonable values for pwrsave */
+			par->hsstrt = 160;
+			par->hsstop = 320;
+			par->vsstrt = 30;
+			par->vsstop = 34;
+		} else {
+			par->hsstrt = 0;
+			par->hsstop = 0;
+			par->vsstrt = 0;
+			par->vsstop = 0;
+		}
+		if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
+			/* PAL video mode */
+			if (par->htotal != PAL_HTOTAL)
+				return -EINVAL;
+			if (par->diwstrt_h < PAL_DIWSTRT_H)
+				return -EINVAL;
+			if (par->diwstrt_v < PAL_DIWSTRT_V)
+				return -EINVAL;
+			hrate = 15625;
+			vrate = 50;
+			if (!IS_OCS) {
+				par->beamcon0 = BMC0_PAL;
+				par->bplcon3 |= BPC3_BRDRBLNK;
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+				par->beamcon0 = BMC0_PAL;
+				par->hsstop = 1;
+			} else if (boot_info.bi_un.bi_ami.vblank != 50)
+				return -EINVAL;
+		} else {
+			/* NTSC video mode
+			 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
+			 * and NTSC activated, so than better let diwstop_h <= 1812
+			 */
+			if (par->htotal != NTSC_HTOTAL)
+				return -EINVAL;
+			if (par->diwstrt_h < NTSC_DIWSTRT_H)
+				return -EINVAL;
+			if (par->diwstrt_v < NTSC_DIWSTRT_V)
+				return -EINVAL;
+			hrate = 15750;
+			vrate = 60;
+			if (!IS_OCS) {
+				par->beamcon0 = 0;
+				par->bplcon3 |= BPC3_BRDRBLNK;
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+				par->beamcon0 = 0;
+				par->hsstop = 1;
+			} else if (boot_info.bi_un.bi_ami.vblank != 60)
+				return -EINVAL;
+		}
+		if (IS_OCS) {
+			if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
+			    par->diwstrt_v >=  512 || par->diwstop_v <  256)
+				return -EINVAL;
+		}
+	} else if (!IS_OCS) {
+		/* Programmable video mode */
+		par->hsstrt = var->right_margin<<clk_shift;
+		par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
+		par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
+		if (!IS_AGA)
+			par->diwstop_h = down4(par->diwstop_h) - 16;
+		par->diwstrt_h = par->diwstop_h - xres_n;
+		par->hbstop = par->diwstrt_h + 4;
+		par->hbstrt = par->diwstop_h + 4;
+		if (par->hbstrt >= par->htotal + 8)
+			par->hbstrt -= par->htotal;
+		par->hcenter = par->hsstrt + (par->htotal >> 1);
+		par->vsstrt = var->lower_margin<<line_shift;
+		par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
+		par->diwstop_v = par->vtotal;
+		if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+			par->diwstop_v -= 2;
+		par->diwstrt_v = par->diwstop_v - yres_n;
+		par->vbstop = par->diwstrt_v - 2;
+		par->vbstrt = par->diwstop_v - 2;
+		if (par->vtotal > 2048 || par->htotal > 2048)
+			return -EINVAL;
+		par->bplcon3 |= BPC3_EXTBLKEN;
+		par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
+		                BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
+		                BMC0_PAL | BMC0_VARCSYEN;
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			par->beamcon0 |= BMC0_HSYTRUE;
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			par->beamcon0 |= BMC0_VSYTRUE;
+		if (var->sync & FB_SYNC_COMP_HIGH_ACT)
+			par->beamcon0 |= BMC0_CSYTRUE;
+		hrate = (amiga_masterclock+par->htotal/2)/par->htotal;
+		vrate = div2(par->vtotal) * par->htotal;
+		vrate = (amiga_masterclock+vrate/2)/vrate;
+	} else
+		return -EINVAL;
 
-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);
-}
+	/*
+	 * Checking the DMA timing
+	 */
 
+	fconst = 16<<maxfmode<<clk_shift;
 
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-   switch (fsfromto) {
-      case 0:
-         memcpy(to, from, len);
-         return;
-      case 1:
-         memcpy_fromfs(to, from, len);
-         return;
-      case 2:
-         memcpy_tofs(to, from, len);
-         return;
-   }
-}
+	/*
+	 * smallest window start value without turn off other dma cycles
+	 * than sprite1-7, unless you change min_fstrt
+	 */
 
 
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-   int size;
-   int tooff = 0, fromoff = 0;
+	fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
+	fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
+	if (fstrt < min_fstrt)
+		return -EINVAL;
 
-   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(u_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);
-}
+	/*
+	 * smallest window start value where smooth scrolling is possible
+	 */
 
+	fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
+	if (fstrt < min_fstrt)
+		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+	maxfetchstop = down16(par->htotal - 80);
+
+	fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
+	fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
+	if (fstrt + fsize > maxfetchstop)
+		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+	fsize = upx(fconst, xres_n);
+	if (fstrt + fsize > maxfetchstop)
+		return -EINVAL;
+
+	if (maxfmode + clk_shift <= 1) {
+		fsize = up64(xres_n + fconst - 1);
+		if (min_fstrt + fsize - 64 > maxfetchstop)
+			par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+		fsize = up64(xres_n);
+		if (min_fstrt + fsize - 64 > maxfetchstop)
+			return -EINVAL;
 
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-   int size = len*sizeof(u_short);
+		fsize -= 64;
+	} else
+		fsize -= fconst;
 
-   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);
-}
+	/*
+	 * Check if there is enough time to update the bitplane pointers for ywrap
+	 */
 
+	if (par->htotal-fsize-64 < par->bpp*64)
+		par->vmode &= ~FB_VMODE_YWRAP;
 
-   /*
-    *    Get the Fixed Part of the Display
-    */
+	/*
+	 * Bitplane calculations and check the Memory Requirements
+	 */
 
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-   struct amiga_fb_par par;
-   int error = 0;
+	if (amifb_ilbm) {
+		par->next_plane = div8(upx(16<<maxfmode, par->vxres));
+		par->next_line = par->bpp*par->next_plane;
+		if (par->next_line * par->vyres > videomemorysize)
+			return -EINVAL;
+	} else {
+		par->next_line = div8(upx(16<<maxfmode, par->vxres));
+		par->next_plane = par->vyres*par->next_line;
+		if (par->next_plane * par->bpp > videomemorysize)
+			return -EINVAL;
+	}
 
-   if (con == -1)
-      amiga_fb_get_par(&par);
-   else
-      error = fbhw->decode_var(&disp[con].var, &par);
-   return(error ? error : fbhw->encode_fix(fix, &par));
-}
+	/*
+	 * Hardware Register Values
+	 */
 
+	par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
+	if (!IS_OCS)
+		par->bplcon0 |= BPC0_ECSENA;
+	if (par->bpp == 8)
+		par->bplcon0 |= BPC0_BPU3;
+	else
+		par->bplcon0 |= par->bpp<<12;
+	if (var->nonstd == FB_NONSTD_HAM)
+		par->bplcon0 |= BPC0_HAM;
+	if (var->sync & FB_SYNC_EXT)
+		par->bplcon0 |= BPC0_ERSY;
+
+	if (IS_AGA)
+		par->fmode = bplfetchmode[maxfmode];
+
+	switch (par->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_INTERLACED:
+			par->bplcon0 |= BPC0_LACE;
+			break;
+		case FB_VMODE_DOUBLE:
+			if (IS_AGA)
+				par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
+			break;
+	}
+
+	if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
+		par->xoffset = var->xoffset;
+		par->yoffset = var->yoffset;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
+				par->xoffset = par->yoffset = 0;
+		} else {
+			if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
+			    par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
+				par->xoffset = par->yoffset = 0;
+		}
+	} else
+		par->xoffset = par->yoffset = 0;
 
-   /*
-    *    Get the User Defined Part of the Display
-    */
+	par->crsr.crsr_x = par->crsr.crsr_y = 0;
+	par->crsr.spot_x = par->crsr.spot_y = 0;
+	par->crsr.height = par->crsr.width = 0;
 
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-   struct amiga_fb_par par;
-   int error = 0;
+	if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
+		return -EINVAL;
 
-   if (con == -1) {
-      amiga_fb_get_par(&par);
-      error = fbhw->encode_var(var, &par);
-   } else
-      *var = disp[con].var;
-   return(error);
+	return 0;
 }
 
+	/*
+	 * Fill the `var' structure based on the values in `par' and maybe
+	 * other values read out of the hardware.
+	 */
 
-static void amiga_fb_set_disp(int con)
+static int ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par)
 {
-   struct fb_fix_screeninfo fix;
+	u_short clk_shift, line_shift;
+	int i;
 
-   amiga_fb_get_fix(&fix, con);
-   if (con == -1)
-      con = 0;
-   disp[con].screen_base = (u_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].line_length = fix.line_length;
-   disp[con].can_soft_blank = 1;
-   disp[con].inverse = amifb_inverse;
-}
+	clk_shift = par->clk_shift;
+	line_shift = par->line_shift;
 
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->vxres;
+	var->yres_virtual = par->vyres;
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
 
-   /*
-    *    Set the User Defined Part of the Display
-    */
+	var->bits_per_pixel = par->bpp;
+	var->grayscale = 0;
 
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-   int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+	if (IS_AGA) {
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->red.msb_right = 0;
+	} else {
+		if (clk_shift == TAG_SHRES) {
+			var->red.offset = 0;
+			var->red.length = 2;
+			var->red.msb_right = 0;
+		} else {
+			var->red.offset = 0;
+			var->red.length = 4;
+			var->red.msb_right = 0;
+		}
+	}
+	var->blue = var->green = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
 
-   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) {
-         amiga_fb_set_disp(con);
-         (*fb_info.changevar)(con);
-         alloc_cmap(&disp[con].cmap, 0, 0);
-         do_install_cmap(con);
-      }
-   }
-   var->activate = 0;
-   return(0);
-}
+	if (par->bplcon0 & BPC0_HAM)
+		var->nonstd = FB_NONSTD_HAM;
+	else
+		var->nonstd = 0;
+	var->activate = 0;
 
+	var->height = -1;
+	var->width = -1;
+	var->accel = 0;
 
-   /*
-    *    Get the Colormap
-    */
+	var->pixclock = pixclock[clk_shift];
 
-static int amiga_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);
-}
+	if (IS_AGA && par->fmode & FMODE_BSCAN2)
+		var->vmode = FB_VMODE_DOUBLE;
+	else if (par->bplcon0 & BPC0_LACE)
+		var->vmode = FB_VMODE_INTERLACED;
+	else
+		var->vmode = FB_VMODE_NONINTERLACED;
 
+	if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
+		var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
+		var->right_margin = par->hsstrt>>clk_shift;
+		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+		var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
+		var->lower_margin = par->vsstrt>>line_shift;
+		var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
+		var->sync = 0;
+		if (par->beamcon0 & BMC0_HSYTRUE)
+			var->sync |= FB_SYNC_HOR_HIGH_ACT;
+		if (par->beamcon0 & BMC0_VSYTRUE)
+			var->sync |= FB_SYNC_VERT_HIGH_ACT;
+		if (par->beamcon0 & BMC0_CSYTRUE)
+			var->sync |= FB_SYNC_COMP_HIGH_ACT;
+	} else {
+		var->sync = FB_SYNC_BROADCAST;
+		var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
+		var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
+		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+		var->vsync_len = 4>>line_shift;
+		var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
+		var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
+		                    var->lower_margin - var->vsync_len;
+	}
 
-   /*
-    *    Set the Colormap
-    */
+	if (par->bplcon0 & BPC0_ERSY)
+		var->sync |= FB_SYNC_EXT;
+	if (par->vmode & FB_VMODE_YWRAP)
+		var->vmode |= FB_VMODE_YWRAP;
 
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-   int err;
+	for (i = 0; i < arraysize(var->reserved); i++)
+		var->reserved[i] = 0;
 
-   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);
+	return 0;
 }
 
+	/*
+	 * Get current hardware setting
+	 */
 
-   /*
-    *    Pan or Wrap the Display
-    *
-    *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-    */
-
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static void ami_get_par(struct amiga_fb_par *par)
 {
-   int err;
-   u_short oldlatch;
-
-   if (var->vmode & FB_VMODE_YWRAP) {
-      if (var->xoffset || var->yoffset >= disp[con].var.yres)
-         return(-EINVAL);
-   } else {
-      if (var->xoffset+disp[con].var.xres > disp[con].var.xres_virtual ||
-          var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
-    return(-EINVAL);
-   }
-   if (con == currcon) {
-      cli();
-      oldlatch = do_vmode;
-      do_vmode = 0;
-      sti();
-      if ((err = fbhw->pan_display(var, &current_par))) {
-         if (oldlatch)
-            do_vmode = 1;
-         return(err);
-      }
-      do_vmode = 1;
-   }
-   disp[con].var.xoffset = var->xoffset;
-   disp[con].var.yoffset = var->yoffset;
-   if (var->vmode & FB_VMODE_YWRAP)
-      disp[con].var.vmode |= FB_VMODE_YWRAP;
-   else
-      disp[con].var.vmode &= ~FB_VMODE_YWRAP;
-   return(0);
+	*par = currentpar;
 }
 
+	/*
+	 * Set new videomode
+	 */
 
-   /*
-    *    Amiga Frame Buffer Specific ioctls
-    */
-
-static int amiga_fb_ioctl(struct inode *inode, struct file *file,
-                          u_int cmd, u_long arg, int con)
+static void ami_set_var(struct fb_var_screeninfo *var)
 {
-   int i;
-   struct fb_fix_cursorinfo crsrfix;
-   struct fb_var_cursorinfo crsrvar;
-   struct fb_cursorstate crsrstate;
-
-   switch (cmd) {
-#ifdef CONFIG_AMIFB_AGA
-      case FBIOGET_FCURSORINFO:
-         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
-         if (i)
-            return(i);
-         i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
-         memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix));
-         return(i);
-      case FBIOGET_VCURSORINFO:
-         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
-         if (i)
-            return(i);
-         i = amiga_fb_get_var_cursorinfo(&crsrvar, con);
-         memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar));
-         return(i);
-      case FBIOPUT_VCURSORINFO:
-         i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
-         if (i)
-            return(i);
-         memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar));
-         i = amiga_fb_set_var_cursorinfo(&crsrvar, con);
-         return(i);
-      case FBIOGET_CURSORSTATE:
-         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
-         if (i)
-            return(i);
-         i = amiga_fb_get_cursorstate(&crsrstate, con);
-         memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate));
-         return(i);
-      case FBIOPUT_CURSORSTATE:
-         i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
-         if (i)
-            return(i);
-         memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate));
-         i = amiga_fb_set_cursorstate(&crsrstate, con);
-         return(i);
-#endif /* CONFIG_AMIFB_AGA */
-#if 1
-      case FBCMD_GET_CURRENTPAR:
-         if ((i = verify_area(VERIFY_WRITE, (void *)arg,
-                              sizeof(struct amiga_fb_par))))
-            return(i);
-         memcpy_tofs((void *)arg, (void *)&current_par,
-                     sizeof(struct amiga_fb_par));
-         return(0);
-         break;
-      case FBCMD_SET_CURRENTPAR:
-         if ((i = verify_area(VERIFY_READ, (void *)arg,
-                              sizeof(struct amiga_fb_par))))
-            return(i);
-         memcpy_fromfs((void *)&current_par, (void *)arg,
-                       sizeof(struct amiga_fb_par));
-         return(0);
-         break;
-#endif
-   }
-   return(-EINVAL);
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
+	ami_decode_var(var, &currentpar);
+	ami_build_copper();
+	do_vmode_full = 1;
+}
+
+#ifdef DEBUG
+static void ami_set_par(struct amiga_fb_par *par)
+{
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
+	currentpar = *par;
+	ami_build_copper();
+	do_vmode_full = 1;
 }
+#endif
 
+	/*
+	 * Pan or Wrap the Display
+	 *
+	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+	 * in `var'.
+	 */
 
-#ifdef CONFIG_AMIFB_AGA
-   /*
-    *    Hardware Cursor
-    */
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static void ami_pan_var(struct fb_var_screeninfo *var)
 {
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_get_fix_cursorinfo(fix, con));
-   return(-EINVAL);
-}
+	struct amiga_fb_par *par = &currentpar;
 
+	par->xoffset = var->xoffset;
+	par->yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		par->vmode |= FB_VMODE_YWRAP;
+	else
+		par->vmode &= ~FB_VMODE_YWRAP;
 
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
-{
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_get_var_cursorinfo(var, con));
-   return(-EINVAL);
+	do_vmode_pan = 0;
+	ami_update_par();
+	do_vmode_pan = 1;
 }
 
+	/*
+	 * Update hardware
+	 */
 
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static int ami_update_par(void)
 {
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_set_var_cursorinfo(var, con));
-   return(-EINVAL);
-}
-
+	struct amiga_fb_par *par = &currentpar;
+	short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
 
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
-{
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_get_cursorstate(state, con));
-   return(-EINVAL);
-}
+	clk_shift = par->clk_shift;
 
+	if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
+		par->xoffset = upx(16<<maxfmode, par->xoffset);
+
+	fconst = 16<<maxfmode<<clk_shift;
+	vshift = modx(16<<maxfmode, par->xoffset);
+	fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
+	fsize = (par->xres+vshift)<<clk_shift;
+	shift = modx(fconst, fstrt);
+	move = downx(2<<maxfmode, div8(par->xoffset));
+	if (maxfmode + clk_shift > 1) {
+		fstrt = downx(fconst, fstrt) - 64;
+		fsize = upx(fconst, fsize);
+		fstop = fstrt + fsize - fconst;
+	} else {
+		mod = fstrt = downx(fconst, fstrt) - fconst;
+		fstop = fstrt + upx(fconst, fsize) - 64;
+		fsize = up64(fsize);
+		fstrt = fstop - fsize + 64;
+		if (fstrt < min_fstrt) {
+			fstop += min_fstrt - fstrt;
+			fstrt = min_fstrt;
+		}
+		move = move - div8((mod-fstrt)>>clk_shift);
+	}
+	mod = par->next_line - div8(fsize>>clk_shift);
+	par->ddfstrt = fstrt;
+	par->ddfstop = fstop;
+	par->bplcon1 = hscroll2hw(shift);
+	par->bpl2mod = mod;
+	if (par->bplcon0 & BPC0_LACE)
+		par->bpl2mod += par->next_line;
+	if (IS_AGA && (par->fmode & FMODE_BSCAN2))
+		par->bpl1mod = -div8(fsize>>clk_shift);
+	else
+		par->bpl1mod = par->bpl2mod;
 
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
-{
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_set_cursorstate(state, con));
-   return(-EINVAL);
-}
-#endif /* CONFIG_AMIFB_AGA */
+	if (par->yoffset) {
+		par->bplpt0 = ZTWO_PADDR((u_long)videomemory + par->next_line*par->yoffset + move);
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if (par->yoffset > par->vyres-par->yres) {
+				par->bplpt0wrap = ZTWO_PADDR((u_long)videomemory + move);
+				if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
+					par->bplpt0wrap += par->next_line;
+			}
+		}
+	} else
+		par->bplpt0 = ZTWO_PADDR((u_long)videomemory + move);
 
+	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
+		par->bplpt0 += par->next_line;
 
-static struct fb_ops amiga_fb_ops = {
-   amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
-   amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
-};
+	return 0;
+}
 
+	/*
+	 * Read a single color register and split it into
+	 * colors/transparent. Return != 0 for invalid regno.
+	 */
 
-void amiga_video_setup(char *options, int *ints)
+static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp)
 {
-   char *this_opt;
-   int i;
-   char mcap_spec[80];
-
-   /*
-    *    Check for a Graphics Board
-    */
-
-#ifdef CONFIG_FB_CYBER
-   if (options && *options)
-      if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
-         amifb_Cyber = 1;
-         Cyber_video_setup(options, ints);
-         return;
-      }
-#endif /* CONFIG_FB_CYBER */
+	if (IS_AGA) {
+		if (regno > 255)
+			return 1;
+	} else {
+		if (regno > 31)
+			return 1;
+	}
 
-#ifdef USE_MONO_AMIFB_IF_NON_AGA
-   if (boot_info.bi_amiga.chipset != CS_AGA) {
-      mono_video_setup(options, ints);
-      return;
-   }
-#endif /* USE_MONO_AMIFB_IF_NON_AGA */
-
-   mcap_spec[0] = '\0';
-   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")) {
-         amifb_inverse = 1;
-         for (i = 0; i < 16; i++) {
-            red16[i] = ~red16[i];
-            green16[i] = ~green16[i];
-            blue16[i] = ~blue16[i];
-         }
-         for (i = 0; i < 8; i++) {
-            red8[i] = ~red8[i];
-            green8[i] = ~green8[i];
-            blue8[i] = ~blue8[i];
-         }
-         for (i = 0; i < 4; i++) {
-            red4[i] = ~red4[i];
-            green4[i] = ~green4[i];
-            blue4[i] = ~blue4[i];
-         }
-         for (i = 0; i < 2; i++) {
-            red2[i] = ~red2[i];
-            green2[i] = ~green2[i];
-            blue2[i] = ~blue2[i];
-         }
-      } else if (!strcmp(this_opt, "ilbm"))
-         amifb_ilbm = 1;
-      else if (!strcmp(this_opt, "pwrsave"))
-         pwrsave = 1;
-      else if (!strncmp(this_opt, "monitorcap:", 11))
-         strcpy(mcap_spec, this_opt+11);
-      else if (!strncmp(this_opt, "font:", 5))
-         strcpy(fb_info.fontname, this_opt+5);
-      else
-         amifb_mode = get_video_mode(this_opt);
-
-   if (*mcap_spec) {
-      char *p;
-      int vmin, vmax, hmin, hmax;
-
-      /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
-       * <V*> vertical freq. in Hz
-       * <H*> horizontal freq. in kHz
-       */
-
-      if (!(p = strtoke(mcap_spec, ";")) || !*p)
-         goto cap_invalid;
-      vmin = simple_strtoul(p, NULL, 10);
-      if (vmin <= 0)
-         goto cap_invalid;
-      if (!(p = strtoke(NULL, ";")) || !*p)
-         goto cap_invalid;
-      vmax = simple_strtoul(p, NULL, 10);
-      if (vmax <= 0 || vmax <= vmin)
-         goto cap_invalid;
-      if (!(p = strtoke(NULL, ";")) || !*p)
-         goto cap_invalid;
-      hmin = 1000 * simple_strtoul(p, NULL, 10);
-      if (hmin <= 0)
-         goto cap_invalid;
-      if (!(p = strtoke(NULL, "")) || !*p)
-         goto cap_invalid;
-      hmax = 1000 * simple_strtoul(p, NULL, 10);
-      if (hmax <= 0 || hmax <= hmin)
-         goto cap_invalid;
-
-      vfmin = vmin;
-      vfmax = vmax;
-      hfmin = hmin;
-      hfmax = hmax;
-cap_invalid:
-      ;
-   }
+	*red = palette[regno].red;
+	*green = palette[regno].green;
+	*blue = palette[regno].blue;
+	return 0;
 }
 
 
-   /*
-    *    Initialization
-    */
+	/*
+	 * 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.
+	 */
 
-struct fb_info *amiga_fb_init(long *mem_start)
+static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp)
 {
-   int err, tag, i;
-   struct fb_var_screeninfo *var;
-
-   /*
-    *    Check for a Graphics Board
-    */
-
-#ifdef CONFIG_FB_CYBER
-   if (amifb_Cyber)
-      return(Cyber_fb_init(mem_start));
-#endif /* CONFIG_FB_CYBER */
+#if defined(CONFIG_AMIFB_AGA)
+	u_short bplcon3 = currentpar.bplcon3;
 
-   /*
-    *    Use the Builtin Chipset
-    */
-
-   if (!AMIGAHW_PRESENT(AMI_VIDEO))
-      return(NULL);
-
-#ifdef USE_MONO_AMIFB_IF_NON_AGA
-   if (boot_info.bi_amiga.chipset != CS_AGA)
-      return(mono_amiga_fb_init(mem_start));
-#endif /* USE_MONO_AMIFB_IF_NON_AGA */
+	if (IS_AGA) {
+		if (regno > 255)
+			return 1;
+	} else
+#endif
+		if (regno > 31)
+			return 1;
 
-   switch (boot_info.bi_amiga.chipset) {
-#ifdef CONFIG_AMIFB_OCS
-      case CS_OCS:
-         strcat(amiga_fb_name, "OCS");
-default_chipset:
-         fbhw = &ocs_switch;
-         maxdepth[TAG_SHRES-1] = 0;       /* OCS means no SHRES */
-         maxdepth[TAG_HIRES-1] = 4;
-         maxdepth[TAG_LORES-1] = 6;
-         break;
-#endif /* CONFIG_AMIFB_OCS */
+	/*
+	 * Update the corresponding Hardware Color Register, unless it's Color
+	 * Register 0 and the screen is blanked.
+	 *
+	 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
+	 * being changed by ami_do_blank() during the VBlank.
+	 */
 
-#ifdef CONFIG_AMIFB_ECS
-      case CS_ECS:
-         strcat(amiga_fb_name, "ECS");
-         fbhw = &ecs_switch;
-         maxdepth[TAG_SHRES-1] = 2;
-         maxdepth[TAG_HIRES-1] = 4;
-         maxdepth[TAG_LORES-1] = 6;
-         break;
-#endif /* CONFIG_AMIFB_ECS */
+	palette[regno].red = red;
+	palette[regno].green = green;
+	palette[regno].blue = blue;
 
-#ifdef CONFIG_AMIFB_AGA
-      case CS_AGA:
-         strcat(amiga_fb_name, "AGA");
-         fbhw = &aga_switch;
-         maxdepth[TAG_SHRES-1] = 8;
-         maxdepth[TAG_HIRES-1] = 8;
-         maxdepth[TAG_LORES-1] = 8;
-         break;
-#endif /* CONFIG_AMIFB_AGA */
+	if (regno || !is_blanked) {
+#if defined(CONFIG_AMIFB_AGA)
+		if (IS_AGA) {
+			VBlankOff();
+			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
+			custom.color[regno&31] = rgb2hw8_high(red, green, blue);
+			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
+			custom.color[regno&31] = rgb2hw8_low(red, green, blue);
+			custom.bplcon3 = bplcon3;
+			VBlankOn();
+		} else
+#endif
+		{
+#if defined(CONFIG_AMIFB_ECS)
+			if (currentpar.bplcon0 & BPC0_SHRES) {
+				u_short color, mask;
+				int i;
+
+				mask = 0x3333;
+				color = rgb2hw2(red, green, blue);
+				VBlankOff();
+				for (i = regno+12; i >= (int)regno; i -= 4)
+					custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+				mask <<=2; color >>= 2;
+				regno = down16(regno)+mul4(mod4(regno));
+				for (i = regno+3; i >= (int)regno; i--)
+					custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+				VBlankOn();
+			} else
+#endif
+				custom.color[regno] = rgb2hw4(red, green, blue);
+		}
+	}
+	return 0;
+}
 
-      default:
-#ifdef CONFIG_AMIFB_OCS
-         printk("Unknown graphics chipset, defaulting to OCS\n");
-         strcat(amiga_fb_name, "Unknown");
-         goto default_chipset;
-#else /* CONFIG_AMIFB_OCS */
-         panic("Unknown graphics chipset, no default driver");
-#endif /* CONFIG_AMIFB_OCS */
-         break;
-   }
+static void ami_update_display(void)
+{
+	struct amiga_fb_par *par = &currentpar;
 
-   /*
-    *    Calculate the Pixel Clock Values for this Machine
-    */
+	custom.bplcon1 = par->bplcon1;
+	custom.bpl1mod = par->bpl1mod;
+	custom.bpl2mod = par->bpl2mod;
+	custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
+	custom.ddfstop = ddfstop2hw(par->ddfstop);
+}
 
-   __asm("movel %3,%%d0;"
-         "movel #0x00000005,%%d1;"     /*  25E9: SHRES:  35 ns / 28 MHz */
-         "movel #0xd21dba00,%%d2;"
-         "divul %%d0,%%d1,%%d2;"
-         "movel %%d2,%0;"
-         "movel #0x0000000b,%%d1;"     /*  50E9: HIRES:  70 ns / 14 MHz */
-         "movel #0xa43b7400,%%d2;"
-         "divul %%d0,%%d1,%%d2;"
-         "movel %%d2,%1;"
-         "movel #0x00000017,%%d1;"     /* 100E9: LORES: 140 ns /  7 MHz */
-         "movel #0x4876e800,%%d2;"
-         "divul %%d0,%%d1,%%d2;"
-         "movel %%d2,%2"
-         : "=r" (pixclock[TAG_SHRES-1]), "=r" (pixclock[TAG_HIRES-1]),
-           "=r" (pixclock[TAG_LORES-1])
-         : "r" (amiga_eclock)
-         : "%%d0", "%%d1", "%%d2");
+	/*
+	 * Change the video mode (called by VBlank interrupt)
+	 */
 
-   /*
-    *    Replace the Tag Values with the Real Pixel Clock Values
-    */
+static void ami_init_display(void)
+{
+	struct amiga_fb_par *par = &currentpar;
 
-   for (i = 0; i < NUM_PREDEF_MODES; i++) {
-      tag = amiga_fb_predefined[i].pixclock;
-      if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
-         amiga_fb_predefined[i].pixclock = pixclock[tag-1];
-         if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag-1])
-            amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag-1];
-      }
-   }
+	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
+	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
+	if (!IS_OCS) {
+		custom.bplcon3 = par->bplcon3;
+		if (IS_AGA)
+			custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+		if (par->beamcon0 & BMC0_VARBEAMEN) {
+			custom.htotal = htotal2hw(par->htotal);
+			custom.hbstrt = hbstrt2hw(par->hbstrt);
+			custom.hbstop = hbstop2hw(par->hbstop);
+			custom.hsstrt = hsstrt2hw(par->hsstrt);
+			custom.hsstop = hsstop2hw(par->hsstop);
+			custom.hcenter = hcenter2hw(par->hcenter);
+			custom.vtotal = vtotal2hw(par->vtotal);
+			custom.vbstrt = vbstrt2hw(par->vbstrt);
+			custom.vbstop = vbstop2hw(par->vbstop);
+			custom.vsstrt = vsstrt2hw(par->vsstrt);
+			custom.vsstop = vsstop2hw(par->vsstop);
+		}
+	}
+	if (!IS_OCS || par->hsstop)
+		custom.beamcon0 = par->beamcon0;
+	if (IS_AGA)
+		custom.fmode = par->fmode;
 
-   err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
-                              NUM_TOTAL_MODES, amiga_fb_predefined);
-   if (err < 0)
-      panic("Cannot register frame buffer");
+	/*
+	 * The minimum period for audio depends on htotal
+	 */
 
-   fbhw->init();
-   check_default_mode();
+	amiga_audio_min_period = div16(par->htotal);
 
-   if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer"))
-      panic("Couldn't add vblank interrupt");
+	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
+#if 1
+	if (is_lace) {
+		if (custom.vposr & 0x8000)
+			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+		else
+			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
+	} else {
+		custom.vposw = custom.vposr | 0x8000;
+		custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+	}
+#else
+	custom.vposw = custom.vposr | 0x8000;
+	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+#endif
+}
 
-   strcpy(fb_info.modename, amiga_fb_name);
-   fb_info.disp = disp;
-   fb_info.switch_con = &amifb_switch;
-   fb_info.updatevar = &amifb_updatevar;
-   fb_info.blank = &amifb_blank;
+	/*
+	 * (Un)Blank the screen (called by VBlank interrupt)
+	 */
 
-   var = &amiga_fb_predefined[amifb_mode];
-   do_fb_set_var(var, 1);
-   strcat(fb_info.modename, " ");
-   strcat(fb_info.modename, amiga_fb_modenames[amifb_mode]);
+static void ami_do_blank(void)
+{
+	struct amiga_fb_par *par = &currentpar;
+#if defined(CONFIG_AMIFB_AGA)
+	u_short bplcon3 = par->bplcon3;
+#endif
+	u_char red, green, blue;
 
-   amiga_fb_get_var(&disp[0].var, -1);
-   amiga_fb_set_disp(-1);
-   do_install_cmap(0);
-   return(&fb_info);
+	if (do_blank > 0) {
+		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
+		red = green = blue = 0;
+		if (!IS_OCS && do_blank > 1) {
+			switch (do_blank) {
+				case 2 : /* suspend vsync */
+					custom.hsstrt = hsstrt2hw(par->hsstrt);
+					custom.hsstop = hsstop2hw(par->hsstop);
+					custom.vsstrt = vsstrt2hw(par->vtotal+4);
+					custom.vsstop = vsstop2hw(par->vtotal+4);
+					break;
+				case 3 : /* suspend hsync */
+					custom.hsstrt = hsstrt2hw(par->htotal+16);
+					custom.hsstop = hsstop2hw(par->htotal+16);
+					custom.vsstrt = vsstrt2hw(par->vsstrt);
+					custom.vsstop = vsstrt2hw(par->vsstop);
+					break;
+				case 4 : /* powerdown */
+					custom.hsstrt = hsstrt2hw(par->htotal+16);
+					custom.hsstop = hsstop2hw(par->htotal+16);
+					custom.vsstrt = vsstrt2hw(par->vtotal+4);
+					custom.vsstop = vsstop2hw(par->vtotal+4);
+					break;
+			}
+			if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
+				custom.htotal = htotal2hw(par->htotal);
+				custom.vtotal = vtotal2hw(par->vtotal);
+				custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
+				                  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
+			}
+		}
+	} else {
+		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
+		red = palette[0].red;
+		green = palette[0].green;
+		blue = palette[0].blue;
+		if (!IS_OCS) {
+			custom.hsstrt = hsstrt2hw(par->hsstrt);
+			custom.hsstop = hsstop2hw(par->hsstop);
+			custom.vsstrt = vsstrt2hw(par->vsstrt);
+			custom.vsstop = vsstop2hw(par->vsstop);
+			custom.beamcon0 = par->beamcon0;
+		}
+	}
+#if defined(CONFIG_AMIFB_AGA)
+	if (IS_AGA) {
+		custom.bplcon3 = bplcon3;
+		custom.color[0] = rgb2hw8_high(red, green, blue);
+		custom.bplcon3 = bplcon3 | BPC3_LOCT;
+		custom.color[0] = rgb2hw8_low(red, green, blue);
+		custom.bplcon3 = bplcon3;
+	} else
+#endif
+	{
+#if defined(CONFIG_AMIFB_ECS)
+		if (par->bplcon0 & BPC0_SHRES) {
+			u_short color, mask;
+			int i;
+
+			mask = 0x3333;
+			color = rgb2hw2(red, green, blue);
+			for (i = 12; i >= 0; i -= 4)
+				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+			mask <<=2; color >>= 2;
+			for (i = 3; i >= 0; i--)
+				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+		} else
+#endif
+			custom.color[0] = rgb2hw4(red, green, blue);
+	}
+	is_blanked = do_blank > 0 ? do_blank : 0;
 }
 
+	/*
+	 * Flash the cursor (called by VBlank interrupt)
+	 */
 
-static int amifb_switch(int con)
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, 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);
+	struct amiga_fb_par *par = &currentpar;
 
-   do_fb_set_var(&disp[con].var, 1);
-   currcon = con;
-   /* Install new colormap */
-   do_install_cmap(con);
-   return(0);
-}
+	fix->crsr_width = fix->crsr_xsize = par->crsr.width;
+	fix->crsr_height = fix->crsr_ysize = par->crsr.height;
+	fix->crsr_color1 = 17;
+	fix->crsr_color2 = 18;
+	return 0;
+}
+
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+{
+	struct amiga_fb_par *par = &currentpar;
+	register u_short *lspr, *sspr;
+	register u_long datawords asm ("d2");
+	register short delta;
+	register u_char color;
+	short height, width, bits, words;
+	int i, size, alloc;
+
+	size = par->crsr.height*par->crsr.width;
+	alloc = var->height*var->width;
+	var->height = par->crsr.height;
+	var->width = par->crsr.width;
+	var->xspot = par->crsr.spot_x;
+	var->yspot = par->crsr.spot_y;
+	if (size > var->height*var->width)
+		return -ENAMETOOLONG;
+	if ((i = verify_area(VERIFY_WRITE, (void *)data, size)))
+		return i;
+	delta = 1<<par->crsr.fmode;
+	lspr = lofsprite + (delta<<1);
+	if (par->bplcon0 & BPC0_LACE)
+		sspr = shfsprite + (delta<<1);
+	else
+		sspr = 0;
+	for (height = (short)var->height-1; height >= 0; height--) {
+		bits = 0; words = delta; datawords = 0;
+		for (width = (short)var->width-1; width >= 0; width--) {
+			if (bits == 0) {
+				bits = 16; --words;
+				asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
+					: "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
+			}
+			--bits;
+			asm volatile (
+				"clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
+				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
+				: "=d" (color), "=d" (datawords) : "1" (datawords));
+			put_fs_byte(color, data++);
+		}
+		if (bits > 0) {
+			--words; ++lspr;
+		}
+		while (--words >= 0)
+			++lspr;
+		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+	}
+	return 0;
+}
+
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+{
+	struct amiga_fb_par *par = &currentpar;
+	register u_short *lspr, *sspr;
+	register u_long datawords asm ("d2");
+	register short delta;
+	u_short fmode;
+	short height, width, bits, words;
+	int i;
 
+	if (!var->width)
+		return -EINVAL;
+	else if (var->width <= 16)
+		fmode = TAG_FMODE_1;
+	else if (var->width <= 32)
+		fmode = TAG_FMODE_2;
+	else if (var->width <= 64)
+		fmode = TAG_FMODE_4;
+	else
+		return -EINVAL;
+	if (fmode > maxfmode)
+		return -EINVAL;
+	if (!var->height)
+		return -EINVAL;
+	if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height)))
+		return i;
+	delta = 1<<fmode;
+	lofsprite = shfsprite = (u_short *)spritememory;
+	lspr = lofsprite + (delta<<1);
+	if (par->bplcon0 & BPC0_LACE) {
+		if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
+			return -EINVAL;
+		memset(lspr, 0, (var->height+4)<<fmode<<2);
+		shfsprite += ((var->height+5)&-2)<<fmode;
+		sspr = shfsprite + (delta<<1);
+	} else {
+		if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
+			return -EINVAL;
+		memset(lspr, 0, (var->height+2)<<fmode<<2);
+		sspr = 0;
+	}
+	for (height = (short)var->height-1; height >= 0; height--) {
+		bits = 16; words = delta; datawords = 0;
+		for (width = (short)var->width-1; width >= 0; width--) {
+			asm volatile (
+				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
+				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
+				: "=d" (datawords) : "0" (datawords), "d" ((u_long)(get_fs_byte(data++))));
+			if (--bits == 0) {
+				bits = 16; --words;
+				asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
+					: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
+			}
+		}
+		if (bits < 16) {
+			--words;
+			asm volatile (
+				"swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
+				"swap %2 ; lslw %4,%2 ; movew %2,%0@+"
+				: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
+		}
+		while (--words >= 0)
+			asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
+				: "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
+		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+	}
+	par->crsr.height = var->height;
+	par->crsr.width = var->width;
+	par->crsr.spot_x = var->xspot;
+	par->crsr.spot_y = var->yspot;
+	par->crsr.fmode = fmode;
+	if (IS_AGA) {
+		par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
+		par->fmode |= sprfetchmode[fmode];
+		custom.fmode = par->fmode;
+	}
+	return 0;
+}
+
+static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
+{
+	struct amiga_fb_par *par = &currentpar;
+
+	state->xoffset = par->crsr.crsr_x;
+	state->yoffset = par->crsr.crsr_y;
+	state->mode = cursormode;
+	return 0;
+}
+
+static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
+{
+	struct amiga_fb_par *par = &currentpar;
+
+	par->crsr.crsr_x = state->xoffset;
+	par->crsr.crsr_y = state->yoffset;
+	if ((cursormode = state->mode) == FB_CURSOR_OFF)
+		cursorstate = -1;
+	do_cursor = 1;
+	return 0;
+}
+
+static void ami_set_sprite(void)
+{
+	struct amiga_fb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_short hs, vs, ve;
+	u_long pl, ps, pt;
+	short mx, my;
+
+	cops = copdisplay.list[currentcop][0];
+	copl = copdisplay.list[currentcop][1];
+	ps = pl = ZTWO_PADDR(dummysprite);
+	mx = par->crsr.crsr_x-par->crsr.spot_x;
+	my = par->crsr.crsr_y-par->crsr.spot_y;
+	if (!(par->vmode & FB_VMODE_YWRAP)) {
+		mx -= par->xoffset;
+		my -= par->yoffset;
+	}
+	if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
+	    mx > -(short)par->crsr.width && mx < par->xres &&
+	    my > -(short)par->crsr.height && my < par->yres) {
+		pl = ZTWO_PADDR(lofsprite);
+		hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
+		vs = par->diwstrt_v + (my<<par->line_shift);
+		ve = vs + (par->crsr.height<<par->line_shift);
+		if (par->bplcon0 & BPC0_LACE) {
+			ps = ZTWO_PADDR(shfsprite);
+			lofsprite[0] = spr2hw_pos(vs, hs);
+			shfsprite[0] = spr2hw_pos(vs+1, hs);
+			if (mod2(vs)) {
+				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
+				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
+				pt = pl; pl = ps; ps = pt;
+			} else {
+				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
+				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
+			}
+		} else {
+			lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
+			lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
+		}
+	}
+	copl[cop_spr0ptrh].w[1] = highw(pl);
+	copl[cop_spr0ptrl].w[1] = loww(pl);
+	if (par->bplcon0 & BPC0_LACE) {
+		cops[cop_spr0ptrh].w[1] = highw(ps);
+		cops[cop_spr0ptrl].w[1] = loww(ps);
+	}
+}
 
-   /*
-    *    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.
-    */
+	/*
+	 * Initialise the Copper Initialisation List
+	 */
 
-static int amifb_updatevar(int con)
+static void ami_init_copper(void)
 {
-   do_vmode = 0;
-   current_par.yoffset = disp[con].var.yoffset;
-   current_par.vmode = disp[con].var.vmode;
-   current_par.bplpt0 = ZTWO_PADDR((u_long)videomemory+
-                                   current_par.yoffset*current_par.next_line);
-   do_vmode = 1;
-   return(0);
-}
+	copins *cop = copdisplay.init;
+	u_long p;
+	int i;
 
+	if (!IS_OCS) {
+		(cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
+		(cop++)->l = CMOVE(0x0181, diwstrt);
+		(cop++)->l = CMOVE(0x0281, diwstop);
+		(cop++)->l = CMOVE(0x0000, diwhigh);
+	} else
+		(cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
+	p = ZTWO_PADDR(dummysprite);
+	for (i = 0; i < 8; i++) {
+		(cop++)->l = CMOVE(0, spr[i].pos);
+		(cop++)->l = CMOVE(highw(p), sprpt[i]);
+		(cop++)->l = CMOVE2(loww(p), sprpt[i]);
+	}
 
-   /*
-    *    Blank the display.
-    */
+	(cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
+	copdisplay.wait = cop;
+	(cop++)->l = CEND;
+	(cop++)->l = CMOVE(0, copjmp2);
+	cop->l = CEND;
 
-static void amifb_blank(int blank)
-{
-   do_blank = blank ? 1 : -1;
+	custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
+	custom.copjmp1 = 0;
 }
 
+static void ami_reinit_copper(void)
+{
+	struct amiga_fb_par *par = &currentpar;
 
-   /*
-    *    VBlank Display Interrupt
-    */
+	copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
+	copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
+}
 
-static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy)
-{
-   static int is_laced = 0;
+	/*
+	 * Build the Copper List
+	 */
 
+static void ami_build_copper(void)
+{
+	struct amiga_fb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_long p;
+
+	currentcop = 1 - currentcop;
+
+	copl = copdisplay.list[currentcop][1];
+
+	(copl++)->l = CWAIT(0, 10);
+	(copl++)->l = CMOVE(par->bplcon0, bplcon0);
+	(copl++)->l = CMOVE(0, sprpt[0]);
+	(copl++)->l = CMOVE2(0, sprpt[0]);
+
+	if (par->bplcon0 & BPC0_LACE) {
+		cops = copdisplay.list[currentcop][0];
+
+		(cops++)->l = CWAIT(0, 10);
+		(cops++)->l = CMOVE(par->bplcon0, bplcon0);
+		(cops++)->l = CMOVE(0, sprpt[0]);
+		(cops++)->l = CMOVE2(0, sprpt[0]);
+
+		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
+		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
+		(cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+		(cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+		if (!IS_OCS) {
+			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
+			                    par->diwstop_h, par->diwstop_v+1), diwhigh);
+			(cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+			                    par->diwstop_h, par->diwstop_v), diwhigh);
+#if 0
+			if (par->beamcon0 & BMC0_VARBEAMEN) {
+				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
+				(copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
+				(cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+				(cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+			}
+#endif
+		}
+		p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
+		(copl++)->l = CMOVE(highw(p), cop2lc);
+		(copl++)->l = CMOVE2(loww(p), cop2lc);
+		p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
+		(cops++)->l = CMOVE(highw(p), cop2lc);
+		(cops++)->l = CMOVE2(loww(p), cop2lc);
+		copdisplay.rebuild[0] = cops;
+	} else {
+		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+		if (!IS_OCS) {
+			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+			                    par->diwstop_h, par->diwstop_v), diwhigh);
 #if 0
-   /*
-    *    This test should be here, in case current_par isn't initialized yet
-    *
-    *    Fortunately only do_flashcursor() will be called in that case, and
-    *    currently that function doesn't use current_par. But this may change
-    *    in future...
-    */
-   if (!current_par_valid)
-      return;
+			if (par->beamcon0 & BMC0_VARBEAMEN) {
+				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+				(copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+			}
 #endif
+		}
+	}
+	copdisplay.rebuild[1] = copl;
 
-   /*
-    *    If interlaced, only change the display on a long frame
-    */
-
-   if (!is_laced || custom.vposr & 0x8000) {
-      if (do_vmode) {
-         fbhw->do_vmode();
-         do_vmode = 0;
-         is_laced = (current_par.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
-      }
-      if (do_movecursor) {
-         fbhw->do_movecursor();
-         do_movecursor = 0;
-      }
-   }
-   if (do_blank) {
-      fbhw->do_blank(do_blank > 0 ? 1 : 0);
-      do_blank = 0;
-   }
-   if (!is_blanked)
-      fbhw->do_flashcursor();
-}
-
-
-   /*
-    *    A strtok which returns empty strings, too
-    */
-
-static char * strtoke(char * s,const char * ct)
-{
-   char *sbegin, *send;
-   static char *ssave = NULL;
-  
-   sbegin  = s ? s : ssave;
-   if (!sbegin)
-      return(NULL);
-   if (*sbegin == '\0') {
-      ssave = NULL;
-      return(NULL);
-   }
-   send = strpbrk(sbegin, ct);
-   if (send && *send != '\0')
-      *send++ = '\0';
-   ssave = send;
-   return(sbegin);
-}
-
-
-   /*
-    *    Get a Video Modes
-    */
-
-static int get_video_mode(const char *name)
-{
-   int i;
-
-   for (i = 1; i < NUM_PREDEF_MODES; i++)
-      if (!strcmp(name, amiga_fb_modenames[i]))
-         return(i);
-   return(0);
-}
-
-
-   /*
-    *    Check the Default Video Mode
-    */
+	ami_update_par();
+	ami_rebuild_copper();
+}
 
-static void check_default_mode(void)
+	/*
+	 * Rebuild the Copper List
+	 *
+	 * We only change the things that are not static
+	 */
+
+static void ami_rebuild_copper(void)
 {
-   struct fb_var_screeninfo var;
+	struct amiga_fb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_short line, h_end1, h_end2;
+	short i;
+	u_long p;
 
-   /* First check the user supplied or system default video mode */
-   if (amifb_mode) {
-      var = amiga_fb_predefined[amifb_mode];
-      var.activate = FB_ACTIVATE_TEST;
-      if (!do_fb_set_var(&var, 1))
-         goto found_video_mode;
-   }
-
-   /* Try some other modes... */
-   printk("Can't use default video mode. Probing video modes...\n");
-   for (amifb_mode = 1; amifb_mode < NUM_PREDEF_MODES; amifb_mode++) {
-      var = amiga_fb_predefined[amifb_mode];
-      var.activate = FB_ACTIVATE_TEST;
-      if (!do_fb_set_var(&var, 1))
-         goto found_video_mode;
-   }
-   panic("Can't find any usable video mode");
+	if (IS_AGA && maxfmode + par->clk_shift == 0)
+		h_end1 = par->diwstrt_h-64;
+	else
+		h_end1 = par->htotal-32;
+	h_end2 = par->ddfstop+64;
+
+	ami_set_sprite();
 
-found_video_mode:
-   amiga_fb_predefined[0] = var;
+	copl = copdisplay.rebuild[1];
+	p = par->bplpt0;
+	if (par->vmode & FB_VMODE_YWRAP) {
+		if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
+			if (par->yoffset > par->vyres-par->yres) {
+				for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+					(copl++)->l = CMOVE(highw(p), bplpt[i]);
+					(copl++)->l = CMOVE2(loww(p), bplpt[i]);
+				}
+				line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
+				while (line >= 512) {
+					(copl++)->l = CWAIT(h_end1, 510);
+					line -= 512;
+				}
+				if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+					(copl++)->l = CWAIT(h_end1, line);
+				else
+					(copl++)->l = CWAIT(h_end2, line);
+				p = par->bplpt0wrap;
+			}
+		} else p = par->bplpt0wrap;
+	}
+	for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+		(copl++)->l = CMOVE(highw(p), bplpt[i]);
+		(copl++)->l = CMOVE2(loww(p), bplpt[i]);
+	}
+	copl->l = CEND;
+
+	if (par->bplcon0 & BPC0_LACE) {
+		cops = copdisplay.rebuild[0];
+		p = par->bplpt0;
+		if (mod2(par->diwstrt_v))
+			p -= par->next_line;
+		else
+			p += par->next_line;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
+				if (par->yoffset > par->vyres-par->yres+1) {
+					for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+						(cops++)->l = CMOVE(highw(p), bplpt[i]);
+						(cops++)->l = CMOVE2(loww(p), bplpt[i]);
+					}
+					line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
+					while (line >= 512) {
+						(cops++)->l = CWAIT(h_end1, 510);
+						line -= 512;
+					}
+					if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+						(cops++)->l = CWAIT(h_end1, line);
+					else
+						(cops++)->l = CWAIT(h_end2, line);
+					p = par->bplpt0wrap;
+					if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
+						p -= par->next_line;
+					else
+						p += par->next_line;
+				}
+			} else p = par->bplpt0wrap - par->next_line;
+		}
+		for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+			(cops++)->l = CMOVE(highw(p), bplpt[i]);
+			(cops++)->l = CMOVE2(loww(p), bplpt[i]);
+		}
+		cops->l = CEND;
+	}
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/amiints.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/amiints.c	Wed Sep 25 10:47:38 1996
@@ -1,15 +1,30 @@
 /*
- * amiints.c -- Amiga Linux interrupt handling code
+ * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
  *
  * 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.
  *
+ * 11/07/96: rewritten interrupt handling, irq lists are exists now only for
+ *           this sources where it makes sense (VERTB/PORTS/EXTER) and you must
+ *           be careful that dev_id for this sources is unique since this the
+ *           only possibility to distinguish between different handlers for
+ *           free_irq. irq lists also have different irq flags:
+ *           - IRQ_FLG_FAST: handler is inserted at top of list (after other
+ *                           fast handlers)
+ *           - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
+ *                           they're executed irq level is set to the previous
+ *                           one, but handlers don't need to be reentrant, if
+ *                           reentrance occured, slow handlers will be just
+ *                           called again.
+ *           The whole interrupt handling for CIAs is moved to cia.c
+ *           /Roman Zippel
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -17,32 +32,33 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 
-/* isr node variables for amiga interrupt sources */
-static isr_node_t *ami_lists[NUM_AMIGA_SOURCES];
+extern int cia_request_irq(struct ciabase *base,int irq,
+                           void (*handler)(int, void *, struct pt_regs *),
+                           unsigned long flags, const char *devname, void *dev_id);
+extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id);
+extern void cia_init_IRQ(struct ciabase *base);
+extern int cia_get_irq_list(struct ciabase *base, char *buf);
+
+/* irq node variables for amiga interrupt sources */
+static irq_node_t *ami_irq_list[AMI_STD_IRQS];
+
+unsigned short ami_intena_vals[AMI_STD_IRQS] = {
+	IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
+	IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
+};
+static const unsigned char ami_servers[AMI_STD_IRQS] = {
+	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
+};
 
-static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = {
-    IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
-    IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS,
-    IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER,
-    IF_SOFT, IF_PORTS, IF_EXTER
-    };
-
-struct ciadata
-{
-    volatile struct CIA *ciaptr;
-    unsigned long	baseirq;
-} ciadata[2];
+static short ami_ablecount[AMI_IRQS];
 
-/*
- * index into ami_lists for IRQs.  CIA IRQs are special, because
- * the same cia interrupt handler is used for both CIAs.
- */
-#define IRQ_IDX(source) (source & ~IRQ_MACHSPEC)
-#define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \
-			     +(source-IRQ_AMIGA_CIAA_TA))
+static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
+{
+	num_spurious += 1;
+}
 
 /*
- * void amiga_init_INTS (void)
+ * void amiga_init_IRQ(void)
  *
  * Parameters:	None
  *
@@ -52,405 +68,428 @@
  * the amiga IRQ handling routines.
  */
 
-static void
-    ami_int1(int irq, struct pt_regs *fp, void *data),
-    ami_int2(int irq, struct pt_regs *fp, void *data),
-    ami_int3(int irq, struct pt_regs *fp, void *data),
-    ami_int4(int irq, struct pt_regs *fp, void *data),
-    ami_int5(int irq, struct pt_regs *fp, void *data),
-    ami_int6(int irq, struct pt_regs *fp, void *data),
-    ami_int7(int irq, struct pt_regs *fp, void *data),
-    ami_intcia(int irq, struct pt_regs *fp, void *data);
-
-void amiga_init_INTS (void)
-{
-    int i;
-
-    /* initialize handlers */
-    for (i = 0; i < NUM_AMIGA_SOURCES; i++)
-	ami_lists[i] = NULL;
-
-    add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler");
-    add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler");
-    add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler");
-    add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler");
-    add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler");
-    add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler");
-    add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler");
-
-    /* hook in the CIA interrupts */
-    ciadata[0].ciaptr = &ciaa;
-    ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA;
-    add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA");
-    ciadata[1].ciaptr = &ciab;
-    ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA;
-    add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB");
-
-    /* turn off all interrupts and enable the master interrupt bit */
-    custom.intena = 0x7fff;
-    custom.intreq = 0x7fff;
-    custom.intena = 0xc000;
-
-    /* turn off all CIA interrupts */
-    ciaa.icr = 0x7f;
-    ciab.icr = 0x7f;
-
-    /* clear any pending CIA interrupts */
-    i = ciaa.icr;
-    i = ciab.icr;
-}
-
-
-/*
- * The builtin Amiga hardware interrupt handlers.
- */
-
-static void ami_int1 (int irq, struct pt_regs *fp, void *data)
+void amiga_init_IRQ(void)
 {
-    ushort ints = custom.intreqr & custom.intenar;
-
-    /* if serial transmit buffer empty, interrupt */
-    if (ints & IF_TBE) {
-	if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) {
-	    call_isr_list (IRQ_AMIGA_TBE,
-			   ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp);
-	    /* 
-	     * don't acknowledge.... 
-	     * allow serial code to turn off interrupts, but
-	     * leave it pending so that when interrupts are
-	     * turned on, transmission will resume
-	     */
-	} else
-	    /* acknowledge the interrupt */
-	    custom.intreq = IF_TBE;
-    }
+	int i;
 
-    /* if floppy disk transfer complete, interrupt */
-    if (ints & IF_DSKBLK) {
-	call_isr_list (IRQ_AMIGA_DSKBLK,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp);
-
-	/* acknowledge */
-	custom.intreq = IF_DSKBLK;
-    }
-
-    /* if software interrupt set, interrupt */
-    if (ints & IF_SOFT) {
-	call_isr_list (IRQ_AMIGA_SOFT,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp);
-
-	/* acknowledge */
-	custom.intreq = IF_SOFT;
-    }
-}
-
-static void ami_int2 (int irq, struct pt_regs *fp, void *data)
-{
-    ushort ints = custom.intreqr & custom.intenar;
+	/* initialize handlers */
+	for (i = 0; i < AMI_STD_IRQS; i++) {
+		if (ami_servers[i]) {
+			ami_irq_list[i] = NULL;
+		} else {
+			ami_irq_list[i] = new_irq_node();
+			ami_irq_list[i]->handler = ami_badint;
+			ami_irq_list[i]->flags   = IRQ_FLG_STD;
+			ami_irq_list[i]->dev_id  = NULL;
+			ami_irq_list[i]->devname = NULL;
+			ami_irq_list[i]->next    = NULL;
+		}
+	}
+	for (i = 0; i < AMI_IRQS; i++)
+		ami_ablecount[i] = 0;
 
-    if (ints & IF_PORTS) {
-	/* call routines which have hooked into the PORTS interrupt */
-	call_isr_list (IRQ_AMIGA_PORTS,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp);
+	/* turn off all interrupts and enable the master interrupt bit */
+	custom.intena = 0x7fff;
+	custom.intreq = 0x7fff;
+	custom.intena = IF_SETCLR | IF_INTEN;
 
-	/* acknowledge */
-	custom.intreq = IF_PORTS;
-    }
+	cia_init_IRQ(&ciaa_base);
+	cia_init_IRQ(&ciab_base);
 }
 
-static void ami_int3 (int irq, struct pt_regs *fp, void *data)
+void amiga_insert_irq(irq_node_t **list, irq_node_t *node)
 {
-    ushort ints = custom.intreqr & custom.intenar;
+	unsigned long flags;
+	irq_node_t *cur;
 
-    /* if a copper interrupt */
-    if (ints & IF_COPER) {
-	call_isr_list (IRQ_AMIGA_COPPER,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
+	if (!node->dev_id)
+		printk("%s: Warning: dev_id of %s is zero\n",
+		       __FUNCTION__, node->devname);
 
-	/* acknowledge */
-	custom.intreq = IF_COPER;
-    }
+	save_flags(flags);
+	cli();
 
-    /* if a vertical blank interrupt */
-    if (ints & IF_VERTB) {
-	call_isr_list (IRQ_AMIGA_VERTB,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
+	cur = *list;
 
-	/* acknowledge */
-	custom.intreq = IF_VERTB;
-    }
+	if (node->flags & IRQ_FLG_FAST) {
+		node->flags &= ~IRQ_FLG_SLOW;
+		while (cur && cur->flags & IRQ_FLG_FAST) {
+			list = &cur->next;
+			cur = cur->next;
+		}
+	} else if (node->flags & IRQ_FLG_SLOW) {
+		while (cur) {
+			list = &cur->next;
+			cur = cur->next;
+		}
+	} else {
+		while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+			list = &cur->next;
+			cur = cur->next;
+		}
+	}
 
-    /* if a blitter interrupt */
-    if (ints & IF_BLIT) {
-	call_isr_list (IRQ_AMIGA_BLIT,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
+	node->next = cur;
+	*list = node;
 
-	/* acknowledge */
-	custom.intreq = IF_BLIT;
-    }
+	restore_flags(flags);
 }
 
-static void ami_int4 (int irq, struct pt_regs *fp, void *data)
+void amiga_delete_irq(irq_node_t **list, void *dev_id)
 {
-    ushort ints = custom.intreqr & custom.intenar;
+	unsigned long flags;
+	irq_node_t *node;
 
-    /* if audio 0 interrupt */
-    if (ints & IF_AUD0) {
-	call_isr_list (IRQ_AMIGA_AUD0,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
+	save_flags(flags);
+	cli();
 
-	/* acknowledge */
-	custom.intreq = IF_AUD0;
-    }
+	for (node = *list; node; list = &node->next, node = *list) {
+		if (node->dev_id == dev_id) {
+			*list = node->next;
+			/* Mark it as free. */
+			node->handler = NULL;
+			restore_flags(flags);
+			return;
+		}
+	}
+	restore_flags(flags);
+	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
+}
 
-    /* if audio 1 interrupt */
-    if (ints & IF_AUD1) {
-	call_isr_list (IRQ_AMIGA_AUD1,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
+/*
+ * amiga_request_irq : add an interrupt service routine for a particular
+ *                     machine specific interrupt source.
+ *                     If the addition was successful, it returns 0.
+ */
 
-	/* acknowledge */
-	custom.intreq = IF_AUD1;
-    }
+int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, const char *devname, void *dev_id)
+{
+	irq_node_t *node;
 
-    /* if audio 2 interrupt */
-    if (ints & IF_AUD2) {
-	call_isr_list (IRQ_AMIGA_AUD2,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
+	if (irq >= AMI_IRQS) {
+		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
 
-	/* acknowledge */
-	custom.intreq = IF_AUD2;
-    }
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB))
+		return cia_request_irq(&ciab_base, irq - IRQ_IDX(IRQ_AMIGA_CIAB),
+		                       handler, flags, devname, dev_id);
+
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA))
+		return cia_request_irq(&ciaa_base, irq - IRQ_IDX(IRQ_AMIGA_CIAA),
+		                       handler, flags, devname, dev_id);
+
+	if (ami_servers[irq]) {
+		if (!(node = new_irq_node()))
+			return -ENOMEM;
+		node->handler = handler;
+		node->flags   = flags;
+		node->dev_id  = dev_id;
+		node->devname = devname;
+		node->next    = NULL;
+		amiga_insert_irq(&ami_irq_list[irq], node);
+	} else {
+		if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) {
+			if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) {
+				printk("%s: IRQ %d from %s is not replaceable\n",
+				       __FUNCTION__, irq, ami_irq_list[irq]->devname);
+				return -EBUSY;
+			}
+			if (flags & IRQ_FLG_REPLACE) {
+				printk("%s: %s can't replace IRQ %d from %s\n",
+				       __FUNCTION__, devname, irq, ami_irq_list[irq]->devname);
+				return -EBUSY;
+			}
+		}
+		ami_irq_list[irq]->handler = handler;
+		ami_irq_list[irq]->flags   = flags;
+		ami_irq_list[irq]->dev_id  = dev_id;
+		ami_irq_list[irq]->devname = devname;
+	}
 
-    /* if audio 3 interrupt */
-    if (ints & IF_AUD3) {
-	call_isr_list (IRQ_AMIGA_AUD3,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
+	/* enable the interrupt */
+	if (irq < IRQ_IDX(IRQ_AMIGA_PORTS)) 
+		custom.intena = IF_SETCLR | ami_intena_vals[irq];
 
-	/* acknowledge */
-	custom.intreq = IF_AUD3;
-    }
+	return 0;
 }
 
-static void ami_int5 (int irq, struct pt_regs *fp, void *data)
+void amiga_free_irq(unsigned int irq, void *dev_id)
 {
-    ushort ints = custom.intreqr & custom.intenar;
+	if (irq >= AMI_IRQS) {
+		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
 
-    /* if serial receive buffer full interrupt */
-    if (ints & IF_RBF) {
-	if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) {
-	    call_isr_list (IRQ_AMIGA_RBF,
-			   ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp);
-	    /* don't acknowledge ; leave that for the handler */
-        } else
-	    /* acknowledge the interrupt */
-	    custom.intreq = IF_RBF;
-    }
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+		cia_free_irq(&ciab_base, irq - IRQ_IDX(IRQ_AMIGA_CIAB), dev_id);
+		return;
+	}
 
-    /* if a disk sync interrupt */
-    if (ints & IF_DSKSYN) {
-	call_isr_list (IRQ_AMIGA_DSKSYN,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+		cia_free_irq(&ciaa_base, irq - IRQ_IDX(IRQ_AMIGA_CIAA), dev_id);
+		return;
+	}
 
-	/* acknowledge */
-	custom.intreq = IF_DSKSYN;
-    }
+	if (ami_servers[irq]) {
+		amiga_delete_irq(&ami_irq_list[irq], dev_id);
+		/* if server list empty, disable the interrupt */
+		if (!ami_irq_list[irq] && irq < IRQ_IDX(IRQ_AMIGA_PORTS))
+			custom.intena = ami_intena_vals[irq];
+	} else {
+		if (ami_irq_list[irq]->dev_id != dev_id)
+			printk("%s: removing probably wrong IRQ %d from %s\n",
+			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
+		ami_irq_list[irq]->handler = ami_badint;
+		ami_irq_list[irq]->flags   = IRQ_FLG_STD;
+		ami_irq_list[irq]->dev_id  = NULL;
+		ami_irq_list[irq]->devname = NULL;
+		custom.intena = ami_intena_vals[irq];
+	}
 }
 
-static void ami_int6 (int irq, struct pt_regs *fp, void *data)
+/*
+ * Enable/disable a particular machine specific interrupt source.
+ * Note that this may affect other interrupts in case of a shared interrupt.
+ * This function should only be called for a _very_ short time to change some
+ * internal data, that may not be changed by the interrupt at the same time.
+ * ami_(enable|disable)_irq calls may also be nested.
+ */
+
+void amiga_enable_irq(unsigned int irq)
 {
-    ushort ints = custom.intreqr & custom.intenar;
+	if (irq >= AMI_IRQS) {
+		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
 
-    if (ints & IF_EXTER) {
-	/* call routines which have hooked into the EXTER interrupt */
-	call_isr_list (IRQ_AMIGA_EXTER,
-		       ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp);
+	if (ami_ablecount[irq]++)
+		return;
 
-	/* acknowledge */
-	custom.intreq = IF_EXTER;
-    }
-}
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+		cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
+		             (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB))));
+		return;
+	}
 
-static void ami_int7 (int irq, struct pt_regs *fp, void *data)
-{
-    panic ("level 7 interrupt received\n");
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
+		             (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA))));
+		return;
+	}
+
+	/* enable the interrupt */
+	custom.intena = IF_SETCLR | ami_intena_vals[irq];
 }
 
-static void ami_intcia (int irq, struct pt_regs *fp, void *data)
+void amiga_disable_irq(unsigned int irq)
 {
-    /* check CIA interrupts */
-    struct ciadata *datap;
-    u_char cia_ints;
+	if (irq >= AMI_IRQS) {
+		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
 
-    /* setup data correctly */
-    if (irq == IRQ_AMIGA_PORTS)
-	    datap = &ciadata[0];
-    else
-	    datap = &ciadata[1];
+	if (--ami_ablecount[irq])
+		return;
 
-    cia_ints = datap->ciaptr->icr;
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+		cia_able_irq(&ciab_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB)));
+		return;
+	}
 
-    /* if timer A interrupt */
-    if (cia_ints & CIA_ICR_TA)
-	call_isr_list (IRQ_AMIGA_CIAA_TA,
-		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp);
+	if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+		cia_able_irq(&ciaa_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA)));
+		return;
+	}
 
-    /* if timer B interrupt */
-    if (cia_ints & CIA_ICR_TB)
-	call_isr_list (IRQ_AMIGA_CIAA_TB,
-		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp);
+	/* disable the interrupt */
+	custom.intena = ami_intena_vals[irq];
+}
 
-    /* if the alarm interrupt */
-    if (cia_ints & CIA_ICR_ALRM)
-	call_isr_list (IRQ_AMIGA_CIAA_ALRM,
-		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp);
+inline void amiga_do_irq(int irq, struct pt_regs *fp)
+{
+	kstat.interrupts[SYS_IRQS + irq]++;
+	ami_irq_list[irq]->handler(irq | IRQ_MACHSPEC, ami_irq_list[irq]->dev_id, fp);
+}
 
-    /* if serial port interrupt (keyboard) */
-    if (cia_ints & CIA_ICR_SP)
-	call_isr_list (IRQ_AMIGA_CIAA_SP,
-		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp);
+void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
+{
+	irq_node_t *node, *slow_nodes;
+	int mach_irq = irq | IRQ_MACHSPEC;
+	unsigned short flags;
 
-    /* if flag interrupt (parallel port) */
-    if (cia_ints & CIA_ICR_FLG)
-	call_isr_list (IRQ_AMIGA_CIAA_FLG,
-		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp);
+	kstat.interrupts[SYS_IRQS + irq]++;
+	if (server->count++)
+		server->reentrance = 1;
+	/* serve first fast and normal handlers */
+	for (node = ami_irq_list[irq];
+	     node && (!(node->flags & IRQ_FLG_SLOW));
+	     node = node->next)
+		node->handler(mach_irq, node->dev_id, fp);
+	custom.intreq = ami_intena_vals[irq];
+	if (!node) {
+		server->count--;
+		return;
+	}
+	save_flags(flags);
+	restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
+	/* if slow handlers exists, serve them now */
+	slow_nodes = node;
+	for (;;) {
+		for (; node; node = node->next)
+			node->handler(mach_irq, node->dev_id, fp);
+		/* if reentrance occured, serve slow handlers again */
+		custom.intena = ami_intena_vals[irq];
+		if (!server->reentrance) {
+			server->count--;
+			custom.intena = IF_SETCLR | ami_intena_vals[irq];
+			return;
+		}
+		server->reentrance = 0;
+		custom.intena = IF_SETCLR | ami_intena_vals[irq];
+		node = slow_nodes;
+	}
 }
 
 /*
- * amiga_add_isr : add an interrupt service routine for a particular
- *		   machine specific interrupt source.
- *		   If the addition was successful, it returns 1, otherwise
- *		   it returns 0.  It will fail if another routine is already
- *		   bound into the specified source.
- *   Note that the "pri" argument is currently unused.
+ * The builtin Amiga hardware interrupt handlers.
  */
 
-int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
-		   *data, char *name)
+static void ami_int1(int irq, void *dev_id, struct pt_regs *fp)
 {
-    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
-    isr_node_t *p;
-
-    if (amiga_source > NUM_AMIGA_SOURCES) {
-	printk ("amiga_add_isr: Unknown interrupt source %ld\n", source);
-	return 0;
-    }
-
-    p = new_isr_node();
-    if (p == NULL)
-	return 0;
-    p->isr = isr;
-    p->pri = pri;
-    p->data = data;
-    p->name = name;
-    p->next = NULL;
-    insert_isr (&ami_lists[amiga_source], p);
-
-    /* enable the interrupt */
-    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
+	unsigned short ints = custom.intreqr & custom.intenar;
 
-    /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
-	ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
+	/* if serial transmit buffer empty, interrupt */
+	if (ints & IF_TBE) {
+		custom.intreq = IF_TBE;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_TBE), fp);
+	}
 
-    /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
-	ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
+	/* if floppy disk transfer complete, interrupt */
+	if (ints & IF_DSKBLK) {
+		custom.intreq = IF_DSKBLK;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_DSKBLK), fp);
+	}
 
-    return 1;
+	/* if software interrupt set, interrupt */
+	if (ints & IF_SOFT) {
+		custom.intreq = IF_SOFT;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_SOFT), fp);
+	}
 }
 
-int amiga_remove_isr (unsigned long source, isrfunc isr, void *data)
+static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
 {
-    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
-
-    if (amiga_source > NUM_AMIGA_SOURCES) {
-	printk ("amiga_remove_isr: Unknown interrupt source %ld\n", source);
-	return 0;
-    }
-
-    delete_isr (&ami_lists[amiga_source], isr, data);
+	unsigned short ints = custom.intreqr & custom.intenar;
+	static struct irq_server server = {0, 0};
 
-    if (ami_lists[amiga_source] == NULL) {
-	/* disable the interrupt */
-	custom.intena = ami_intena_vals[amiga_source];
+	/* if a blitter interrupt */
+	if (ints & IF_BLIT) {
+		custom.intreq = IF_BLIT;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp);
+	}
 
-	/* if a CIAA interrupt, disable the appropriate CIA ICR bit */
-	if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
-	    ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
-
-	/* if a CIAB interrupt, disable the appropriate CIA ICR bit */
-	if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
-	    ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
-    }
+	/* if a copper interrupt */
+	if (ints & IF_COPER) {
+		custom.intreq = IF_COPER;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_COPPER), fp);
+	}
 
-    return 1;
+	/* if a vertical blank interrupt */
+	if (ints & IF_VERTB)
+		amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server);
 }
 
-
-/*
- * Enable/disable a particular machine specific interrupt source.
- * Note that this may affect other interrupts in case of a shared interrupt.
- */
-
-void amiga_enable_irq(unsigned int source)
+static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
 {
-    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
+	unsigned short ints = custom.intreqr & custom.intenar;
 
-    if (amiga_source > NUM_AMIGA_SOURCES) {
-	printk("amiga_enable_irq: Unknown interrupt source %d\n", source);
-	return;
-    }
-
-    /* enable the interrupt */
-    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
+	/* if audio 0 interrupt */
+	if (ints & IF_AUD0) {
+		custom.intreq = IF_AUD0;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD0), fp);
+	}
 
-    /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
-	ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
+	/* if audio 1 interrupt */
+	if (ints & IF_AUD1) {
+		custom.intreq = IF_AUD1;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD1), fp);
+	}
 
-    /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
-	ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
+	/* if audio 2 interrupt */
+	if (ints & IF_AUD2) {
+		custom.intreq = IF_AUD2;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD2), fp);
+	}
 
+	/* if audio 3 interrupt */
+	if (ints & IF_AUD3) {
+		custom.intreq = IF_AUD3;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD3), fp);
+	}
 }
 
-void amiga_disable_irq(unsigned int source)
+static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
 {
-    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
-
-    if (amiga_source > NUM_AMIGA_SOURCES) {
-	printk("amiga_disable_irq: Unknown interrupt source %d\n", source);
-	return;
-    }
+	unsigned short ints = custom.intreqr & custom.intenar;
 
-    /* disable the interrupt */
-    custom.intena = ami_intena_vals[amiga_source];
-
-    /* if a CIAA interrupt, disable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
-	ciaa.icr = 1 << (source - IRQ_AMIGA_CIAA_TA);
+	/* if serial receive buffer full interrupt */
+	if (ints & IF_RBF) {
+		/* acknowledge of IF_RBF must be done by the serial interrupt */
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_RBF), fp);
+	}
 
-    /* if a CIAB interrupt, disable the appropriate CIA ICR bit */
-    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
-	ciab.icr = 1 << (source - IRQ_AMIGA_CIAB_TA);
+	/* if a disk sync interrupt */
+	if (ints & IF_DSKSYN) {
+		custom.intreq = IF_DSKSYN;
+		amiga_do_irq(IRQ_IDX(IRQ_AMIGA_DSKSYN), fp);
+	}
+}
 
+static void ami_int7(int irq, void *dev_id, struct pt_regs *fp)
+{
+	panic ("level 7 interrupt received\n");
 }
 
+void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	ami_badint, ami_int1, ami_badint, ami_int3,
+	ami_int4, ami_int5, ami_badint, ami_int7
+};
 
-int amiga_get_irq_list( char *buf, int len )
-{	int			i;
-    isr_node_t	*p;
+int amiga_get_irq_list(char *buf)
+{
+	int i, len = 0;
+	irq_node_t *node;
 
-	for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
-		if (!ami_lists[i])
+	for (i = 0; i < AMI_STD_IRQS; i++) {
+		if (!(node = ami_irq_list[i]))
 			continue;
-		len += sprintf( buf+len, "ami  %2d: ???????? ", i );
-		for( p = ami_lists[i]; p; p = p->next ) {
-			len += sprintf( buf+len, "%s\n", p->name );
-			if (p->next)
-				len += sprintf( buf+len, "                  " );
-		}
+		if (node->flags & IRQ_FLG_STD)
+			continue;
+		len += sprintf(buf+len, "ami  %2d: %10u ", i,
+		               kstat.interrupts[SYS_IRQS + i]);
+		do {
+			if (ami_servers[i]) {
+				if (node->flags & IRQ_FLG_FAST)
+					len += sprintf(buf+len, "F ");
+				else if (node->flags & IRQ_FLG_SLOW)
+					len += sprintf(buf+len, "S ");
+				else
+					len += sprintf(buf+len, "  ");
+			} else {
+				if (node->flags & IRQ_FLG_LOCK)
+					len += sprintf(buf+len, "L ");
+				else
+					len += sprintf(buf+len, "  ");
+			}
+			len += sprintf(buf+len, "%s\n", node->devname);
+			if ((node = node->next))
+				len += sprintf(buf+len, "                    ");
+		} while (node);
 	}
-	
-	return( len );
+
+	len += cia_get_irq_list(&ciaa_base, buf+len);
+	len += cia_get_irq_list(&ciab_base, buf+len);
+	return len;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/amikeyb.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/amikeyb.c	Wed Sep 25 10:47:38 1996
@@ -1,7 +1,7 @@
 /*
- * linux/amiga/amikeyb.c
+ * linux/arch/m68k/amiga/amikeyb.c
  *
- * Amiga Keyboard driver for 680x0 Linux
+ * Amiga Keyboard driver for Linux/m68k
  *
  * 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
@@ -21,18 +21,19 @@
 #include <linux/timer.h>
 #include <linux/kd.h>
 #include <linux/random.h>
+#include <linux/kernel.h>
 
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/amigatypes.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
 
-extern int do_poke_blanked_console;
-extern void process_keycode (int);
+extern void handle_scancode(unsigned char);
 
 #define AMIKEY_CAPS	(0x62)
 #define BREAK_MASK	(0x80)
+#define RESET_WARNING	(0xf0)	/* before rotation */
 
 static u_short amiplain_map[NR_KEYS] = {
 	0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
@@ -46,7 +47,7 @@
 	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -65,7 +66,7 @@
 	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
-	0xf112, 0xf113, 0xf208, 0xf203, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -84,7 +85,7 @@
 	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
-	0xf514, 0xf515, 0xf208, 0xf202, 0xf30d, 0xf30c, 0xf30a, 0xf516,
+	0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -103,7 +104,7 @@
 	0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf208, 0xf204, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -122,7 +123,7 @@
 	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf200, 0xf30d, 0xf30c, 0xf30a, 0xf200,
+	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -141,7 +142,7 @@
 	0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
-	0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf50a,
+	0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -160,7 +161,7 @@
 	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf200, 0xf30d, 0xf30c, 0xf30a, 0xf200,
+	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
 	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
@@ -175,30 +176,31 @@
 static unsigned int key_repeat_rate  = DEFAULT_KEYB_REP_RATE;
 
 static unsigned char rep_scancode;
-static void amikeyb_rep (unsigned long ignore);
+static void amikeyb_rep(unsigned long ignore);
 static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
 
 extern struct pt_regs *pt_regs;
 
-static void amikeyb_rep (unsigned long ignore)
+static void amikeyb_rep(unsigned long ignore)
 {
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-
-	pt_regs = NULL;
-
-	amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
-	amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
-	add_timer(&amikeyb_rep_timer);
-	process_keycode (rep_scancode);
+    unsigned long flags;
+    save_flags(flags);
+    cli();
+
+    pt_regs = NULL;
+
+    amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
+    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
+    add_timer(&amikeyb_rep_timer);
+    handle_scancode(rep_scancode);
 
-	restore_flags(flags);
+    restore_flags(flags);
 }
 
-static void keyboard_interrupt (int irq, struct pt_regs *fp, void *dummy)
+static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
     unsigned char scancode, break_flag;
+    static int reset_warning = 0;
 
     /* save frame for register dump */
     pt_regs = (struct pt_regs *)fp;
@@ -208,49 +210,94 @@
 
     /* switch SP pin to output for handshake */
     ciaa.cra |= 0x40;
+
+    /*
+     *  On receipt of the second RESET_WARNING, we must not pull KDAT high
+     *  again to delay the hard reset as long as possible.
+     *
+     *  Note that not all keyboards send reset warnings...
+     */
+    if (reset_warning)
+	if (scancode == RESET_WARNING) {
+	    printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
+		   "The system will be reset within 10 seconds!!\n");
+	    /* Panic doesn't sync from within an interrupt, so we do nothing */
+	    return;
+	} else
+	    /* Probably a mistake, cancel the alert */
+	    reset_warning = 0;
+
     /* wait until 85 us have expired */
     udelay(85);
     /* switch CIA serial port to input mode */
     ciaa.cra &= ~0x40;
 
+    mark_bh(KEYBOARD_BH);
+
     /* rotate scan code to get up/down bit in proper position */
     __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode));
 
     /*
-     * do machine independent keyboard processing of "normalized" scancode
-     * A "normalized" scancode is one that an IBM PC might generate
      * Check make/break first
      */
     break_flag = scancode & BREAK_MASK;
     scancode &= (unsigned char )~BREAK_MASK;
 
     if (scancode == AMIKEY_CAPS) {
-	    /* if the key is CAPS, fake a press/release. */
-	    process_keycode (AMIKEY_CAPS);
-	    process_keycode (BREAK_MASK | AMIKEY_CAPS);
-    } else {
-	    /* handle repeat */
-	    if (break_flag) {
-		    del_timer(&amikeyb_rep_timer);
-		    rep_scancode = 0;
-	    } else {
-		    del_timer(&amikeyb_rep_timer);
-		    rep_scancode = break_flag | scancode;
-		    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
-		    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
-		    add_timer(&amikeyb_rep_timer);
-	    }
-	    process_keycode (break_flag | scancode);
-    }
-
-    do_poke_blanked_console = 1;
-    mark_bh(CONSOLE_BH);
-    add_keyboard_randomness(scancode);
-
-    return;
+	/* if the key is CAPS, fake a press/release. */
+	handle_scancode(AMIKEY_CAPS);
+	handle_scancode(BREAK_MASK | AMIKEY_CAPS);
+    } else if (scancode < 0x78) {
+	/* handle repeat */
+	if (break_flag) {
+	    del_timer(&amikeyb_rep_timer);
+	    rep_scancode = 0;
+	} else {
+	    del_timer(&amikeyb_rep_timer);
+	    rep_scancode = scancode;
+	    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
+	    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
+	    add_timer(&amikeyb_rep_timer);
+	}
+	handle_scancode(break_flag | scancode);
+    } else
+	switch (scancode) {
+	    case 0x78:
+		reset_warning = 1;
+		break;
+	    case 0x79:
+		printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
+		break;
+	    case 0x7a:
+		printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
+		break;
+#if 0 /* obsolete according to the HRM */
+	    case 0x7b:
+		printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
+		break;
+#endif
+	    case 0x7c:
+		printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
+		break;
+	    case 0x7d:
+		printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
+		break;
+	    case 0x7e:
+		printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
+		break;
+#if 0 /* obsolete according to the HRM */
+	    case 0x7f:
+		printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
+		break;
+#endif
+	    default:
+		printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
+		       break_flag | scancode);
+		break;
+	}
 }
 
-int amiga_keyb_init (void)
+int amiga_keyb_init(void)
 {
     if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
         return -EIO;
@@ -263,7 +310,7 @@
     key_maps[5]  = amishift_ctrl_map;
     key_maps[8]  = amialt_map;
     key_maps[12] = amictrl_alt_map;
-    memcpy (plain_map, amiplain_map, sizeof(plain_map));
+    memcpy(plain_map, amiplain_map, sizeof(plain_map));
 
     /*
      * Initialize serial data direction.
@@ -273,28 +320,27 @@
     /*
      * arrange for processing of keyboard interrupt
      */
-    add_isr (IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, NULL, "keyboard");
+    request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
 
     return 0;
 }
 
 int amiga_kbdrate( struct kbd_repeat *k )
-
 {
-	if (k->delay > 0) {
-		/* convert from msec to jiffies */
-		key_repeat_delay = (k->delay * HZ + 500) / 1000;
-		if (key_repeat_delay < 1)
-			key_repeat_delay = 1;
-	}
-	if (k->rate > 0) {
-		key_repeat_rate = (k->rate * HZ + 500) / 1000;
-		if (key_repeat_rate < 1)
-			key_repeat_rate = 1;
-	}
+    if (k->delay > 0) {
+	/* convert from msec to jiffies */
+	key_repeat_delay = (k->delay * HZ + 500) / 1000;
+	if (key_repeat_delay < 1)
+            key_repeat_delay = 1;
+    }
+    if (k->rate > 0) {
+	key_repeat_rate = (k->rate * HZ + 500) / 1000;
+	if (key_repeat_rate < 1)
+            key_repeat_rate = 1;
+    }
 
-	k->delay = key_repeat_delay * 1000 / HZ;
-	k->rate  = key_repeat_rate  * 1000 / HZ;
-	
-	return( 0 );
+    k->delay = key_repeat_delay * 1000 / HZ;
+    k->rate  = key_repeat_rate  * 1000 / HZ;
+    
+    return( 0 );
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/amisound.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/amisound.c	Wed Sep 25 10:47:38 1996
@@ -1,7 +1,7 @@
 /*
- * linux/amiga/amisound.c
+ * linux/arch/m68k/amiga/amisound.c
  *
- * amiga sound driver for 680x0 Linux
+ * amiga sound driver for Linux/m68k
  *
  * 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
@@ -11,9 +11,9 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 
+#include <asm/amigatypes.h>
 #include <asm/system.h>
 #include <asm/amigahw.h>
-#include <asm/bootinfo.h>
 
 static u_short *snd_data = NULL;
 static const signed char sine_data[] = {
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/chipram.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/chipram.c	Wed Sep 25 10:47:38 1996
@@ -8,7 +8,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/amigahw.h>
 
 struct chip_desc {
@@ -22,6 +22,17 @@
 #define DP(ptr) ((struct chip_desc *)(ptr))
 
 static unsigned long chipsize;
+static unsigned long chipavail; /*MILAN*/
+
+/*MILAN*/
+unsigned long amiga_chip_avail( void )
+{
+#ifdef DEBUG
+   printk("chip_avail : %ld bytes\n",chipavail);
+#endif
+   return chipavail;
+}
+
 
 void amiga_chip_init (void)
 {
@@ -46,6 +57,7 @@
   
   dp->alloced = 0;
   dp->length = chipsize - 2*sizeof(*dp);
+  chipavail = dp->length;  /*MILAN*/
 
 #ifdef DEBUG
   printk ("chipram end boundary is %p, length is %d\n", dp,
@@ -63,7 +75,7 @@
 	size = (size + 7) & ~7;
 
 #ifdef DEBUG
-	printk ("chip_alloc: allocate %ld bytes\n", size);
+   printk("chip_alloc: allocate %ld bytes\n", size);
 #endif
 
 	/*
@@ -121,7 +133,9 @@
 	if ((unsigned long)ptr & 7)
 		panic("chip_alloc: alignment violation\n");
 
-	return ptr;
+    chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
+
+    return ptr;
 }
 
 void amiga_chip_free (void *ptr)
@@ -129,6 +143,10 @@
 	struct chip_desc *sdp = DP(ptr) - 1, *dp2;
 	struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
 
+    chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
+#ifdef DEBUG
+   printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
+#endif
 	/* deallocate the chunk */
 	sdp->alloced = edp->alloced = 0;
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/cia.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/cia.c	Wed Sep 25 10:47:38 1996
@@ -0,0 +1,190 @@
+/*
+ *  linux/arch/m68k/amiga/cia.c - CIA support
+ *
+ *  Copyright (C) 1996 Roman Zippel
+ *
+ *  The concept of some functions bases on the original Amiga OS function
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+struct ciabase {
+	volatile struct CIA *cia;
+	u_char icr_mask, icr_data;
+	u_short int_mask;
+	int handler_irq, cia_irq, server_irq;
+	char *name;
+	struct irq_server server;
+	irq_handler_t irq_list[CIA_IRQS];
+} ciaa_base = {
+	&ciaa, 0, 0, IF_PORTS,
+	IRQ2, IRQ_AMIGA_CIAA,
+	IRQ_IDX(IRQ_AMIGA_PORTS),
+	"CIAA handler", {0, 0}
+}, ciab_base = {
+	&ciab, 0, 0, IF_EXTER,
+	IRQ6, IRQ_AMIGA_CIAB,
+	IRQ_IDX(IRQ_AMIGA_EXTER),
+	"CIAB handler", {0, 0}
+};
+
+/*
+ *  Cause or clear CIA interrupts, return old interrupt status.
+ */
+
+unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
+{
+	u_char old;
+
+	old = (base->icr_data |= base->cia->icr);
+	if (mask & CIA_ICR_SETCLR)
+		base->icr_data |= mask;
+	else
+		base->icr_data &= ~mask;
+	if (base->icr_data & base->icr_mask)
+		custom.intreq = IF_SETCLR | base->int_mask;
+	return (old & base->icr_mask);
+}
+
+/*
+ *  Enable or disable CIA interrupts, return old interrupt mask,
+ *  interrupts will only be enabled if a handler exists
+ */
+
+unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
+{
+	u_char old, tmp;
+	int i;
+
+	old = base->icr_mask;
+	base->icr_data |= base->cia->icr;
+	base->cia->icr = mask;
+	if (mask & CIA_ICR_SETCLR)
+		base->icr_mask |= mask;
+	else
+		base->icr_mask &= ~mask;
+	base->icr_mask &= CIA_ICR_ALL;
+	for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
+		if ((tmp & base->icr_mask) && !base->irq_list[i].handler)
+			base->icr_mask &= ~tmp;
+ 	}
+	if (base->icr_data & base->icr_mask)
+		custom.intreq = IF_SETCLR | base->int_mask;
+	return (old);
+}
+
+int cia_request_irq(struct ciabase *base, unsigned int irq,
+                    void (*handler)(int, void *, struct pt_regs *),
+                    unsigned long flags, const char *devname, void *dev_id)
+{
+	u_char mask;
+
+	if (!(base->irq_list[irq].flags & IRQ_FLG_STD)) {
+		if (base->irq_list[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %ld from %s is not replaceable\n",
+			       __FUNCTION__, IRQ_IDX(base->cia_irq + irq),
+			       base->irq_list[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %ld from %s\n", __FUNCTION__,
+			       devname, IRQ_IDX(base->cia_irq + irq),
+			       base->irq_list[irq].devname);
+			return -EBUSY;
+		}
+	}
+	base->irq_list[irq].handler = handler;
+	base->irq_list[irq].flags   = flags;
+	base->irq_list[irq].dev_id  = dev_id;
+	base->irq_list[irq].devname = devname;
+
+	/* enable the interrupt */
+	mask = 1 << irq;
+	cia_set_irq(base, mask);
+	cia_able_irq(base, CIA_ICR_SETCLR | mask);
+	return 0;
+}
+
+void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
+{
+	if (base->irq_list[irq].dev_id != dev_id)
+		printk("%s: removing probably wrong IRQ %ld from %s\n",
+		       __FUNCTION__, IRQ_IDX(base->cia_irq + irq),
+		       base->irq_list[irq].devname);
+
+	base->irq_list[irq].handler = NULL;
+	base->irq_list[irq].flags   = IRQ_FLG_STD;
+
+	cia_able_irq(base, 1 << irq);
+}
+
+static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct ciabase *base = (struct ciabase *)dev_id;
+	int mach_irq, i;
+	unsigned char ints;
+
+	mach_irq = base->cia_irq;
+	irq = SYS_IRQS + IRQ_IDX(mach_irq);
+	ints = cia_set_irq(base, CIA_ICR_ALL);
+	custom.intreq = base->int_mask;
+	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
+		if (ints & 1) {
+			kstat.interrupts[irq]++;
+			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
+		}
+		ints >>= 1;
+	}
+	amiga_do_irq_list(base->server_irq, fp, &base->server);
+}
+
+void cia_init_IRQ(struct ciabase *base)
+{
+	int i;
+
+	/* init isr handlers */
+	for (i = 0; i < CIA_IRQS; i++) {
+		base->irq_list[i].handler = NULL;
+		base->irq_list[i].flags   = IRQ_FLG_STD;
+	}
+
+	/* clear any pending interrupt and turn off all interrupts */
+	cia_set_irq(base, CIA_ICR_ALL);
+	cia_able_irq(base, CIA_ICR_ALL);
+
+	/* install CIA handler */
+	request_irq(base->handler_irq, cia_handler, IRQ_FLG_LOCK, base->name, base);
+
+	custom.intena = IF_SETCLR | base->int_mask;
+}
+
+int cia_get_irq_list(struct ciabase *base, char *buf)
+{
+	int i, j, len = 0;
+
+	j = IRQ_IDX(base->cia_irq);
+	for (i = 0; i < CIA_IRQS; i++) {
+		if (!(base->irq_list[i].flags & IRQ_FLG_STD)) {
+			len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
+			               kstat.interrupts[SYS_IRQS + j + i]);
+			if (base->irq_list[i].flags & IRQ_FLG_LOCK)
+				len += sprintf(buf+len, "L ");
+			else
+				len += sprintf(buf+len, "  ");
+			len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
+		}
+	}
+	return len;
+}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/config.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/config.c	Wed Sep 25 10:47:38 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/amiga/config.c
+ *  linux/arch/m68k/amiga/config.c
  *
  *  Copyright (C) 1993 Hamish Macdonald
  *
@@ -20,11 +20,10 @@
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
-#include <linux/linkage.h>
 
+#include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
-#include <asm/bootinfo.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
@@ -35,15 +34,20 @@
 
 extern char m68k_debug_device[];
 
-extern void amiga_sched_init(isrfunc handler);
+extern void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *));
+/* amiga specific keyboard functions */
 extern int amiga_keyb_init(void);
 extern int amiga_kbdrate (struct kbd_repeat *);
-extern void amiga_init_INTS (void);
-extern int amiga_add_isr (unsigned long, isrfunc, int, void *, char *);
-extern int amiga_remove_isr (unsigned long, isrfunc, void *);
-extern int amiga_get_irq_list (char *, int);
-extern void amiga_enable_irq(unsigned int);
-extern void amiga_disable_irq(unsigned int);
+/* amiga specific irq functions */
+extern void amiga_init_IRQ (void);
+extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
+extern int amiga_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                              unsigned long flags, const char *devname, void *dev_id);
+extern int amiga_free_irq (unsigned int irq, void *dev_id);
+extern void amiga_enable_irq (unsigned int);
+extern void amiga_disable_irq (unsigned int);
+extern int amiga_get_irq_list (char *);
+/* amiga specific timer functions */
 extern unsigned long amiga_gettimeoffset (void);
 extern void a3000_gettod (int *, int *, int *, int *, int *, int *);
 extern void a2000_gettod (int *, int *, int *, int *, int *, int *);
@@ -199,7 +203,7 @@
       switch (custom.deniseid & 0xf) {
       case 0x0c:
 	AMIGAHW_SET(DENISE_HR);
-	printk("DENISE_HR");
+	printk("DENISE_HR ");
 	break;
       case 0x08:
 	AMIGAHW_SET(LISA);
@@ -257,9 +261,10 @@
   mach_sched_init      = amiga_sched_init;
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
-  mach_init_INTS       = amiga_init_INTS;
-  mach_add_isr         = amiga_add_isr;
-  mach_remove_isr      = amiga_remove_isr;
+  mach_init_IRQ        = amiga_init_IRQ;
+  mach_default_handler = &amiga_default_handler;
+  mach_request_irq     = amiga_request_irq;
+  mach_free_irq        = amiga_free_irq;
   mach_enable_irq      = amiga_enable_irq;
   mach_disable_irq     = amiga_disable_irq;
   mach_get_irq_list    = amiga_get_irq_list;
@@ -330,60 +335,24 @@
 #endif /* CONFIG_ZORRO */
 }
 
-extern long time_finetune;	/* from kernel/sched.c */
-
 static unsigned short jiffy_ticks;
 
-#if 1 /* ++1.3++ */
-static void timer_wrapper( int irq, struct pt_regs *fp, void *otimerf )
- {
-   unsigned short flags, old_flags;
-
-   ciab.icr = 0x01;
-
-   save_flags(flags);
-   old_flags = (flags & ~0x0700) | (fp->sr & 0x0700);
-   
-   restore_flags(old_flags);
-
-   (*(isrfunc)otimerf)( irq, fp, NULL );
-
-   restore_flags(flags);
-   ciab.icr = 0x81;
-}
-#endif
-
-void amiga_sched_init (isrfunc timer_routine)
+void amiga_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
 {
+	jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
-#if 0 /* XXX */ /* I think finetune was removed by the 1.3.29 patch */
-    double finetune;
-#endif
-
-    jiffy_ticks = (amiga_eclock+50)/100;
-#if 0 /* XXX */
-    finetune = (jiffy_ticks-amiga_eclock/HZ)/amiga_eclock*1000000*(1<<24);
-    time_finetune = finetune+0.5;
-#endif
-
-    ciab.cra &= 0xC0;	 /* turn off timer A, continuous mode, from Eclk */
-    ciab.talo = jiffy_ticks % 256;
-    ciab.tahi = jiffy_ticks / 256;
-    /* CIA interrupts when counter underflows, so adjust ticks by 1 */
-    jiffy_ticks -= 1;
-
-    /* install interrupt service routine for CIAB Timer A */
-    /*
-     * Please don't change this to use ciaa, as it interferes with the
-     * SCSI code. We'll have to take a look at this later
-     */
-#if 0
-    add_isr (IRQ_AMIGA_CIAB_TA, timer_routine, 0, NULL, "timer");
-#else
-    add_isr (IRQ_AMIGA_CIAB_TA, timer_wrapper, 0, timer_routine, "timer");
-#endif
-    /* start timer */
-    ciab.cra |= 0x01;
+	ciab.cra &= 0xC0;	 /* turn off timer A, continuous mode, from Eclk */
+	ciab.talo = jiffy_ticks % 256;
+	ciab.tahi = jiffy_ticks / 256;
+
+	/* install interrupt service routine for CIAB Timer A
+	 *
+	 * Please don't change this to use ciaa, as it interferes with the
+	 * SCSI code. We'll have to take a look at this later
+	 */
+	request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
+	/* start timer */
+	ciab.cra |= 0x11;
 }
 
 #define TICK_SIZE 10000
@@ -391,33 +360,30 @@
 /* This is always executed with interrupts disabled.  */
 unsigned long amiga_gettimeoffset (void)
 {
-    unsigned short hi, lo, hi2;
-    unsigned long ticks, offset = 0;
+	unsigned short hi, lo, hi2;
+	unsigned long ticks, offset = 0;
 
-    /* read CIA A timer A current value */
-    hi	= ciab.tahi;
-    lo	= ciab.talo;
-    hi2 = ciab.tahi;
-
-    if (hi != hi2) {
-	lo = ciab.talo;
-	hi = hi2;
-    }
+	/* read CIA B timer A current value */
+	hi  = ciab.tahi;
+	lo  = ciab.talo;
+	hi2 = ciab.tahi;
+
+	if (hi != hi2) {
+		lo = ciab.talo;
+		hi = hi2;
+	}
 
-    ticks = hi << 8 | lo;
+	ticks = hi << 8 | lo;
 
-#if 0 /* XXX */
-/* reading the ICR clears all interrupts.  bad idea! */
-      if (ticks > jiffy_ticks - jiffy_ticks / 100)
-	/* check for pending interrupt */
-	if (ciab.icr & CIA_ICR_TA)
-	  offset = 10000;
-#endif
+	if (ticks > jiffy_ticks / 2)
+		/* check for pending interrupt */
+		if (cia_set_irq(&ciab_base, 0) & CIA_ICR_TA)
+			offset = 10000;
 
-    ticks = (jiffy_ticks-1) - ticks;
-    ticks = (10000 * ticks) / jiffy_ticks;
+	ticks = jiffy_ticks - ticks;
+	ticks = (10000 * ticks) / jiffy_ticks;
 
-    return ticks + offset;
+	return ticks + offset;
 }
 
 void a3000_gettod (int *yearp, int *monp, int *dayp,
@@ -657,7 +623,7 @@
   unsigned long jmp_addr = VTOP(&&jmp_addr_label);
 
   cli();
-  if (m68k_is040or060)
+  if (CPU_IS_040_OR_060)
     /* Setup transparent translation registers for mapping
      * of 16 MB kernel segment before disabling translation
      */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/cyberfb.c linux/arch/m68k/amiga/cyberfb.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/cyberfb.c	Tue May 21 19:51:42 1996
+++ linux/arch/m68k/amiga/cyberfb.c	Wed Sep 25 10:47:38 1996
@@ -29,11 +29,9 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
-#include <linux/config.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <asm/bootinfo.h>
 #include <asm/zorro.h>
 #include <asm/pgtable.h>
 #include <linux/fb.h>
@@ -331,7 +329,8 @@
   }
 
 *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-CyberMem = kernel_map (board_addr + 0x01400000, 0x00400000,
+/* This includes the video memory as well as the S3 register set */
+CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
                        KERNELMAP_NOCACHE_SER, memstart);
 
 if (Cyberfb_Cyber8)
@@ -339,8 +338,7 @@
 else
   memset ((char*)CyberMem, 0, CYBER16_WIDTH * CYBER16_HEIGHT);
 
-CyberRegs = (char*) kernel_map (board_addr + 0x02000000, 0xf000,
-                                KERNELMAP_NOCACHE_SER, memstart);
+CyberRegs = (char*) (CyberMem + 0x00c00000);
 
 /* Disable hardware cursor */
 *(CyberRegs + S3_CRTC_ADR)  = S3_REG_LOCK2;
@@ -410,7 +408,11 @@
 
    strcpy(fix->id, Cyber_fb_name);
    fix->smem_start = CyberMem;
+#if 0
    fix->smem_len = CyberSize;
+#else
+   fix->smem_len = 0x01000000;
+#endif
 
    fix->type = FB_TYPE_PACKED_PIXELS;
    fix->type_aux = 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/ksyms.c linux/arch/m68k/amiga/ksyms.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/ksyms.c	Mon May 20 07:54:25 1996
+++ linux/arch/m68k/amiga/ksyms.c	Wed Sep 25 10:47:38 1996
@@ -1,5 +1,7 @@
 #include <linux/module.h>
 #include <asm/zorro.h>
+#include <asm/amigatypes.h>
+#include <asm/amigahw.h>
 
 static struct symbol_table mach_amiga_symbol_table = {
 #include <linux/symtab_begin.h>
@@ -7,11 +9,16 @@
   /*
    * Add things here when you find the need for it.
    */
+  X(amiga_colorclock),
+  X(amiga_chip_alloc),
+  X(amiga_chip_free),
+  X(amiga_chip_avail),
 
   X(zorro_find),
   X(zorro_get_board),
   X(zorro_config_board),
   X(zorro_unconfig_board),
+  X(zorro_unused_z2ram),
 
   /* example
   X(something_you_need),
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- lx2.0/v2.0.21/linux/arch/m68k/amiga/zorro.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/amiga/zorro.c	Wed Sep 25 10:47:38 1996
@@ -13,9 +13,9 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <asm/setup.h>
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
-#include <asm/bootinfo.h>
 #include <asm/zorro.h>
 
 
@@ -69,12 +69,23 @@
     *             long (max. 80 characters per board identification line)
     */
 
+BEGIN_PROD(PACIFIC)
+   PROD("SE 2000 A500", SE_2000_A500)
+   PROD("HD Controller", PACIFIC_HD)
+END
+
+BEGIN_PROD(KUPKE)
+   PROD("Golem RAM Box 2MB", GOLEM_BOX_2)
+END
+
 BEGIN_PROD(MEMPHIS)
    PROD("Stormbringer", STORMBRINGER)
 END
 
 BEGIN_PROD(COMMODORE2)
-   PROD("A2088 Bridgeboard", A2088)
+   PROD("A2088 XT Bridgeboard", A2088)
+   PROD("A2286 AT Bridgeboard", A2286)
+   PROD("A4091 SCSI Controller", A4091_2)
    PROD("A2386-SX Bridgeboard", A2386SX)
 END
 
@@ -91,22 +102,68 @@
    PROD("A2620 68020/RAM Card", A2620)
    PROD("A2630 68030/RAM Card", A2630)
    PROD("A4091 SCSI Controller", A4091)
+   PROD("A2065 Ethernet Card", A2065_2)
    PROD("Romulator Card", ROMULATOR)
    PROD("A3000 Test Fixture", A3000TESTFIX)
+   PROD("A2386-SX Bridgeboard", A2386SX_2)
    PROD("A2065 Ethernet Card", A2065)
 END
 
+BEGIN_PROD(COMMODORE3)
+   PROD("A2090A Combitec/MacroSystem", A2090A_CM)
+END
+
+BEGIN_PROD(KCS)
+   PROD("KCS Power PC Board", POWER_BOARD)
+END
+
 BEGIN_PROD(CARDCO)
+   PROD("Kronos 2000 SCSI Controller", KRONOS_2000_SCSI)
+   PROD("A1000 SCSI Controller", A1000_SCSI)
+   PROD("Escort SCSI Controller", ESCORT_SCSI)
    PROD("Cardco A2410 Hires Graphics card", CC_A2410)
 END
 
+BEGIN_PROD(A_SQUARED)
+   PROD("Live! 2000", LIVE_2000)
+END
+
+BEGIN_PROD(COMSPEC)
+   PROD("AX2000", AX2000)
+END
+
+BEGIN_PROD(ANAKIN)
+   PROD("Easyl Tablet", EASYL)
+END
+
 BEGIN_PROD(MICROBOTICS)
+   PROD("StarBoard II", STARBOARD_II)
+   PROD("StarDrive", STARDRIVE)
+   PROD("8-Up (Rev A)", 8_UP_A)
+   PROD("8-Up (Rev Z)", 8_UP_Z)
+   PROD("VXL RAM", VXL_RAM)
    PROD("VXL-30 Turbo Board", VXL_30)
+   PROD("MBX 1200", MBX_1200)
+   PROD("Hardframe 2000", HARDFRAME_2000)
+   PROD("MBX 1200", MBX_1200_2)
+END
+
+BEGIN_PROD(ACCESS)
+END
+
+BEGIN_PROD(EXPANSION_TECH)
 END
 
 BEGIN_PROD(ASDG)
+   PROD("Memory Expansion", ASDG_MEMORY)
+   PROD("Memory Expansion", ASDG_MEMORY_2)
    PROD("Lan Rover Ethernet", LAN_ROVER)
-   PROD("Dual Serial Card", ASDG_DUAL_SERIAL)
+   PROD("Twin-X Serial Card", TWIN_X)
+END
+
+BEGIN_PROD(IMTRONICS)
+   PROD("Hurricane 2800 68030", HURRICANE_2800)
+   PROD("Hurricane 2800 68030", HURRICANE_2800_2)
 END
 
 BEGIN_PROD(UNIV_OF_LOWELL)
@@ -120,9 +177,15 @@
 END
 
 BEGIN_PROD(SUPRA)
+   PROD("SupraDrive 4x4 SCSI Controller", SUPRADRIVE_4x4)
+   PROD("2000 DMA HD", SUPRA_2000)
+   PROD("500 HD/RAM", SUPRA_500)
+   PROD("500RX/2000 RAM", SUPRA_500RX)
+   PROD("500RX/2000 RAM", SUPRA_500RX_2)
+   PROD("2400zi Modem", SUPRA_2400ZI)
    PROD("Wordsync SCSI Controller", WORDSYNC)
    PROD("Wordsync II SCSI Controller", WORDSYNC_II)
-   PROD("2400 Modem", SUPRA_2400MODEM)
+   PROD("2400zi+ Modem", SUPRA_2400ZIPLUS)
 END
 
 BEGIN_PROD(CSA)
@@ -130,21 +193,35 @@
    PROD("12 Gauge SCSI Controller", 12GAUGE)
 END
 
+BEGIN_PROD(GVP3)
+   PROD("Impact SCSI/Memory", IMPACT)
+END
+
+BEGIN_PROD(BYTEBOX)
+   PROD("A500", BYTEBOX_A500)
+END
+
 BEGIN_PROD(POWER_COMPUTING)
-   PROD("Viper II Turbo Board (DKB 1240)", DKB_1240)
+   PROD("DKB 3128 RAM", DKB_3128)
+   PROD("DKB Cobra / Viper II Turbo Board", VIPER_II_COBRA)
 END
 
 BEGIN_PROD(GVP)
+   PROD("Impact Series-I SCSI 4K", IMPACT_I_4K)
+   PROD("Impact Series-I SCSI 16K/2", IMPACT_I_16K_2)
+   PROD("Impact Series-I SCSI 16K/3", IMPACT_I_16K_3)
+   PROD("Impact 3001 IDE", IMPACT_3001_IDE)
+/* PROD("Impact 3001 RAM", IMPACT_3001_RAM) */
    PROD("Generic GVP product", GVP)
    PROD("Series II SCSI Controller", GVPIISCSI)
    PROD("Series II SCSI Controller", GVPIISCSI_2)
    PROD("Series II RAM", GVPIIRAM)
    PROD("A2000 68030 Turbo Board", GVP_A2000_030)
+/* PROD("Impact 3001 IDE", IMPACT_3001_IDE_2) */
    PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI)
    PROD("IV-24 Graphics Board", GVPIV_24)
-/*
-   PROD("I/O Extender", GVPIO_EXT)
-*/
+   PROD("GFORCE 040 Turbo Board", GFORCE_040)
+/* PROD("I/O Extender", GVPIO_EXT) */
 END
 
 BEGIN_GVP_PROD
@@ -164,6 +241,14 @@
    GVP_PROD("SERIES-II SCSI controller", SERIESII)
 END
 
+BEGIN_PROD(SYNERGY)
+END
+
+BEGIN_PROD(XETEC)
+   PROD("FastCard SCSI Controller", FASTCARD_SCSI)
+   PROD("FastCard RAM", FASTCARD_RAM)
+END
+
 BEGIN_PROD(PPI)
    PROD("Mercury Turbo Board", MERCURY)
    PROD("PP&S A3000 68040 Turbo Board", PPS_A3000_040)
@@ -172,12 +257,23 @@
    PROD("PP&S A500 68040 Turbo Board", PPS_A500_040)
 END
 
+BEGIN_PROD(SPIRIT)
+   PROD("HDA 506 Harddisk", HDA_506)
+   PROD("OctaByte RAM", OCTABYTE_RAM)
+END
+
 BEGIN_PROD(BSC)
    PROD("ALF 3 SCSI Controller", ALF_3_SCSI)
 END
 
+BEGIN_PROD(BSC3)
+   PROD("ALF 2 SCSI Controller", ALF_2_SCSI)
+   PROD("ALF 3 SCSI Controller", ALF_3_SCSI_2)
+END
+
 BEGIN_PROD(C_LTD)
    PROD("Kronos SCSI Controller", KRONOS_SCSI)
+   PROD("A1000 SCSI Controller", A1000_SCSI_2)
 END
 
 BEGIN_PROD(JOCHHEIM)
@@ -188,26 +284,29 @@
    PROD("Serial Solution", SERIAL_SOLUTION)
 END
 
-BEGIN_PROD(GOLEM)
-   PROD("Golem SCSI-II Controller", GOLEM_SCSI_II)
+BEGIN_PROD(ICD)
+   PROD("Advantage 2000 SCSI Controller", ADVANTAGE_2000)
 END
 
-BEGIN_PROD(HARDITAL_SYNTHES)
-   PROD("SCSI Controller", HARDITAL_SCSI)
+BEGIN_PROD(KUPKE2)
+   PROD("Golem SCSI-II Controller", KUPKE_SCSI_II)
+   PROD("Golem Box", GOLEM_BOX)
+   PROD("Golem SCSI/AT Controller", KUPKE_SCSI_AT)
 END
 
-BEGIN_PROD(HARDITAL2)
+BEGIN_PROD(HARDITAL)
    PROD("TQM 68030+68882 Turbo Board", TQM)
 END
 
 BEGIN_PROD(BSC2)
    PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI)
-   PROD("Tandem", TANDEM)
+   PROD("Tandem AT-2008/508 IDE Controller", TANDEM)
    PROD("Oktagon 2008 RAM", OKTAGON_RAM)
    PROD("Alfa Data MultiFace I", MULTIFACE_I)
    PROD("Alfa Data MultiFace II", MULTIFACE_II)
    PROD("Alfa Data MultiFace III", MULTIFACE_III)
-   PROD("ISDN Master", ISDN_MASTER)
+   PROD("ISDN MasterCard", ISDN_MASTERCARD)
+   PROD("ISDN MasterCard II", ISDN_MASTERCARD_2)
 END
 
 BEGIN_PROD(ADV_SYS_SOFT)
@@ -215,13 +314,26 @@
    PROD("Nexus RAM", NEXUS_RAM)
 END
 
+BEGIN_PROD(IMPULSE)
+   PROD("FireCracker 24", FIRECRACKER_24)
+END
+
 BEGIN_PROD(IVS)
-   PROD("Trumpcard 500 SCSI Controller", TRUMPCARD_500)
-   PROD("Trumpcard SCSI Controller", TRUMPCARD)
+   PROD("GrandSlam RAM", GRANDSLAM)
+   PROD("OverDrive HD", IVS_OVERDRIVE)
+   PROD("Trumpcard Classic SCSI Controller", TRUMPCARD_CLASSIC)
+   PROD("Trumpcard Pro SCSI Controller", TRUMPCARD_PRO)
+   PROD("Meta-4 RAM", META_4)
    PROD("Vector SCSI Controller", VECTOR)
 END
 
+BEGIN_PROD(VECTOR)
+   PROD("Connection Serial IO", CONNECTION)
+END
+
 BEGIN_PROD(XPERT_PRODEV)
+   PROD("Visiona Graphics Board (RAM)", VISIONA_RAM)
+   PROD("Visiona Graphics Board (REG)", VISIONA_REG)
    PROD("Merlin Graphics Board (RAM)", MERLIN_RAM)
    PROD("Merlin Graphics Board (REG)", MERLIN_REG)
 END
@@ -230,8 +342,27 @@
    PROD("Amiganet Board", AMIGANET)
 END
 
-BEGIN_PROD(DIG_MICRONICS)
+BEGIN_PROD(SUNRIZE)
+   PROD("AD516 Audio", AD516)
+END
+
+BEGIN_PROD(TRICERATOPS)
+   PROD("Multi I/O Board", TRICERATOPS)
+END
+
+BEGIN_PROD(APPLIED_MAGIC)
    PROD("DMI Resolver Graphics Board", DMI_RESOLVER)
+   PROD("Digital Broadcaster", DIGITAL_BCASTER)
+END
+
+BEGIN_PROD(GFX_BASE)
+   PROD("GDA-1 Graphics Board (RAM)", GDA_1_RAM)
+   PROD("GDA-1 Graphics Board (REG)", GDA_1_REG)
+END
+
+BEGIN_PROD(ROCTEC)
+   PROD("RH 800C Hard Disk Controller", RH_800C)
+   PROD("RH 800C RAM", RH_800C_RAM)
 END
 
 BEGIN_PROD(HELFRICH1)
@@ -242,10 +373,23 @@
    PROD("GG2+ Bus Converter", GG2PLUS)
 END
 
+BEGIN_PROD(MASOBOSHI)
+   PROD("Master Card RAM", MASTER_CARD_RAM)
+   PROD("Master Card SCSI Controller", MASTER_CARD_SCSI)
+   PROD("MVD 819", MVD_819)
+END
+
+BEGIN_PROD(DELACOMP)
+   PROD("RAM Expansion 2000", DELACOMP_RAM_2000)
+END
+
 BEGIN_PROD(VILLAGE_TRONIC)
-   PROD("Ariadne Ethernet Card", ARIADNE)
+   PROD("Domino Graphics Board (RAM)", DOMINO_RAM)
+   PROD("Domino Graphics Board (REG)", DOMINO_REG)
    PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM)
    PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG)
+   PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG_2)
+   PROD("Ariadne Ethernet Card", ARIADNE)
 END
 
 BEGIN_PROD(UTILITIES_ULTD)
@@ -253,51 +397,98 @@
    PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2)
 END
 
+BEGIN_PROD(AMITRIX)
+   PROD("Multi-IO", AMITRIX_MULTI_IO)
+   PROD("CD-RAM Memory", AMITRIX_CD_RAM)
+END
+
 BEGIN_PROD(MTEC)
    PROD("68030 Turbo Board", MTEC_68030)
-   PROD("T1230/28 Turbo Board", MTEC_T1230)
+   PROD("A1200 T68030/42 RTC Turbo Board", MTEC_T1230)
+   PROD("8MB RAM", MTEC_RAM)
 END
 
 BEGIN_PROD(GVP2)
-   PROD("Spectrum Graphics Board (RAM)", SPECTRUM_RAM)
-   PROD("Spectrum Graphics Board (REG)", SPECTRUM_REG)
+   PROD("EGS 28/24 Spectrum Graphics Board (RAM)", SPECTRUM_RAM)
+   PROD("EGS 28/24 Spectrum Graphics Board (REG)", SPECTRUM_REG)
 END
 
 BEGIN_PROD(HELFRICH2)
    PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM)
    PROD("Piccolo Graphics Board (REG)", PICCOLO_REG)
    PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS)
+   PROD("VideoCruncher", VIDEOCRUNCHER)
    PROD("SD64 Graphics Board (RAM)", SD64_RAM)
    PROD("SD64 Graphics Board (REG)", SD64_REG)
 END
 
 BEGIN_PROD(MACROSYSTEMS)
-   PROD("Warp Engine SCSI Controller", WARP_ENGINE)
+   PROD("Warp Engine 40xx SCSI Controller", WARP_ENGINE)
+END
+
+BEGIN_PROD(ELBOX)
+   PROD("Elbox 1200/4 RAM", ELBOX_1200)
 END
 
 BEGIN_PROD(HARMS_PROF)
+   PROD("030 plus", HARMS_030_PLUS)
    PROD("3500 Turbo board", 3500_TURBO)
 END
 
+BEGIN_PROD(MICRONIK)
+   PROD("RCA 120 RAM", RCA_120)
+END
+
+BEGIN_PROD(IMTRONICS2)
+   PROD("Hurricane 2800 68030", HURRICANE_2800_3)
+   PROD("Hurricane 2800 68030", HURRICANE_2800_4)
+END
+
+BEGIN_PROD(KUPKE3)
+   PROD("Golem HD 3000", GOLEM_3000)
+END
+
+BEGIN_PROD(INFORMATION)
+   PROD("ISDN Engine I", ISDN_ENGINE_I)
+END
+
 BEGIN_PROD(VORTEX)
-   PROD("Golden Gate 80386 Board", GOLDEN_GATE_386)
+   PROD("Golden Gate 80386SX Board", GOLDEN_GATE_386SX)
    PROD("Golden Gate RAM", GOLDEN_GATE_RAM)
    PROD("Golden Gate 80486 Board", GOLDEN_GATE_486)
 END
 
 BEGIN_PROD(DATAFLYER)
-   PROD("4000SX SCSI Controller", DATAFLYER_4000SX)
+   PROD("4000SX SCSI Controller", DATAFLYER_4000SXS)
+   PROD("4000SX RAM", DATAFLYER_4000SXR)
+END
+
+BEGIN_PROD(READYSOFT)
+   PROD("AMax II/IV", AMAX)
 END
 
 BEGIN_PROD(PHASE5)
+   PROD("Blizzard RAM", BLIZZARD_RAM)
+   PROD("Blizzard", BLIZZARD)
+   PROD("Blizzard 1220-IV Turbo Board", BLIZZARD_1220_IV)
    PROD("FastLane RAM", FASTLANE_RAM)
-   PROD("FastLane/Blizzard 1230-II SCSI Controller", FASTLANE_SCSI)
-   PROD("CyberStorm Fast SCSI-II Controller", CYBERSTORM_SCSI)
+   PROD("FastLane/Blizzard 1230-II/CyberSCSI", FASTLANE_SCSI)
+   PROD("Blizzard 1220/CyberStorm", CYBERSTORM_SCSI)
    PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III)
-   PROD("Blizzard 1230-IV Turbo Board", BLIZZARD_1230_IV)
+   PROD("Blizzard 1230-IV/1260 Turbo Board", BLIZZARD_1230_IV)
+   PROD("Blizzard 2060 SCSI Controller", BLIZZARD_2060SCSI)
+   PROD("CyberStorm", CYBERSTORM)
    PROD("CyberVision64 Graphics Board", CYBERVISION)
 END
 
+BEGIN_PROD(DPS)
+   PROD("Personal Animation Recorder", DPS_PAR)
+END
+
+BEGIN_PROD(APOLLO2)
+   PROD("A620 68020 Accelerator", A620)
+END
+
 BEGIN_PROD(APOLLO)
    PROD("AT-Apollo", AT_APOLLO)
    PROD("Turbo Board", APOLLO_TURBO)
@@ -313,52 +504,107 @@
    PROD("Maestro Pro", MAESTRO_PRO)
    PROD("Retina Z2 Graphics Board", RETINA_Z2)
    PROD("MultiEvolution", MULTI_EVOLUTION)
+   PROD("Toccata Sound Board", TOCCATA)
    PROD("Retina Z3 Graphics Board", RETINA_Z3)
+   PROD("VLab Motion", VLAB_MOTION)
    PROD("Falcon '040 Turbo Board", FALCON_040)
 END
 
+BEGIN_PROD(COMBITEC)
+END
+
+BEGIN_PROD(SKI)
+   PROD("SCSI / Dual Serial", SKI_SCSI_SERIAL)
+END
+
+BEGIN_PROD(CAMERON)
+   PROD("Scanner Interface", CAMERON_SCANNER)
+END
+
+BEGIN_PROD(REIS_WARE)
+   PROD("Handyscanner", RW_HANDYSCANNER)
+END
+
+
 BEGIN_MANUF
+   MANUF("Pacific Peripherals", PACIFIC)
+   MANUF("Kupke", KUPKE)
    MANUF("Memphis", MEMPHIS)
    MANUF("Commodore", COMMODORE2)
    MANUF("Commodore", COMMODORE)
+   MANUF("Commodore", COMMODORE3)
+   MANUF("Kolff Computer Supplies", KCS)
    MANUF("Cardco", CARDCO)
+   MANUF("A-Squared", A_SQUARED)
+   MANUF("ComSpec Communications", COMSPEC)
+   MANUF("Anakin", ANAKIN)
    MANUF("MicroBotics", MICROBOTICS)
+   MANUF("Access Associates", ACCESS)
+   MANUF("Expansion Technologies", EXPANSION_TECH)
    MANUF("ASDG", ASDG)
+   MANUF("Imtronics", IMTRONICS)
    MANUF("University of Lowell", UNIV_OF_LOWELL)
    MANUF("Ameristar", AMERISTAR)
    MANUF("Supra", SUPRA)
    MANUF("CSA", CSA)
+   MANUF("Great Valley Products", GVP3)
+   MANUF("ByteBox", BYTEBOX)
    MANUF("Power Computing", POWER_COMPUTING)
    MANUF("Great Valley Products", GVP)
+   MANUF("Synergy", SYNERGY)
+   MANUF("Xetec", XETEC)
    MANUF("Progressive Peripherals", PPI)
+   MANUF("Spirit", SPIRIT)
    MANUF("BSC", BSC)
+   MANUF("BSC", BSC3)
    MANUF("C Ltd.", C_LTD)
    MANUF("Jochheim", JOCHHEIM)
    MANUF("Checkpoint Technologies", CHECKPOINT)
-   MANUF("Golem", GOLEM)
-   MANUF("Hardital Synthesis", HARDITAL_SYNTHES)
-   MANUF("Hardital Synthesis", HARDITAL2)
+   MANUF("ICD", ICD)
+   MANUF("Kupke", KUPKE2)
+   MANUF("Hardital Synthesis", HARDITAL)
    MANUF("BSC", BSC2)
    MANUF("Advanced Systems & Software", ADV_SYS_SOFT)
+   MANUF("Impulse", IMPULSE)
    MANUF("IVS", IVS)
+   MANUF("Vector", VECTOR)
    MANUF("XPert/ProDev", XPERT_PRODEV)
    MANUF("Hydra Systems", HYDRA_SYSTEMS)
-   MANUF("Digital Micronics", DIG_MICRONICS)
+   MANUF("Sunrize Industries", SUNRIZE)
+   MANUF("Triceratops", TRICERATOPS)
+   MANUF("Applied Magic", APPLIED_MAGIC)
+   MANUF("GFX-Base", GFX_BASE)
+   MANUF("RocTec", ROCTEC)
    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)
    MANUF("MTEC", MTEC)
    MANUF("Great Valley Products", GVP2)
    MANUF("Helfrich", HELFRICH2)
    MANUF("MacroSystems", MACROSYSTEMS)
+   MANUF("ElBox Computer", ELBOX)
    MANUF("Harms Professional", HARMS_PROF)
+   MANUF("Micronik", MICRONIK)
+   MANUF("Imtronics", IMTRONICS2)
+   MANUF("Kupke", KUPKE3)
+   MANUF("Information", INFORMATION)
    MANUF("Vortex", VORTEX)
    MANUF("DataFlyer", DATAFLYER)
+   MANUF("ReadySoft", READYSOFT)
    MANUF("Phase5", PHASE5)
+   MANUF("DPS", DPS)
+   MANUF("Apollo", APOLLO2)
    MANUF("Apollo", APOLLO)
    MANUF("Uwe Gerlach", UWE_GERLACH)
    MANUF("MacroSystems", MACROSYSTEMS2)
+   MANUF("Combitec", COMBITEC)
+   MANUF("SKI Peripherals", SKI)
+   MANUF("Cameron", CAMERON)
+   MANUF("Reis-Ware", REIS_WARE)
 END
 
 #define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer))
@@ -511,7 +757,7 @@
                   break;
                } else {
                   epc = *(enum GVP_ident *)ZTWO_VADDR(addr+0x8000) &
-                        GVP_EPCMASK;
+                        GVP_PRODMASK;
                   for (k = 0; k < NUM_GVP_PROD; k++)
                      if (Ext_Prod_GVP[k].ID == epc) {
                         prodname = Ext_Prod_GVP[k].Name;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/atari/Makefile	Mon May  6 12:44:30 1996
+++ linux/arch/m68k/atari/Makefile	Wed Sep 25 10:47:38 1996
@@ -11,7 +11,6 @@
 
 O_TARGET := atari.o
 O_OBJS	 := config.o atakeyb.o ataints.o \
-            stdma.o atasound.o joystick.o stram.o atafb.o
-OX_OBJS = ksyms.o
+            stdma.o atasound.o joystick.o stram.o atafb.o ksyms.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/atafb.c	Mon Jul 15 09:55:11 1996
+++ linux/arch/m68k/atari/atafb.c	Wed Sep 25 10:47:38 1996
@@ -39,6 +39,7 @@
 #define ATAFB_FALCON
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -46,13 +47,13 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
-#include <asm/bootinfo.h>
 
 #include <linux/fb.h>
 #include <asm/atarikb.h>
@@ -83,10 +84,6 @@
 static int ovsc_offset=0, ovsc_addlen=0;
 int        ovsc_switchmode=0;
 
-#ifdef ATAFB_FALCON
-static int pwrsave = 0;	/* use VESA suspend mode instead of blanking only? */
-#endif
-
 static struct atari_fb_par {
 	unsigned long screen_base;
 	int vyres;
@@ -282,9 +279,12 @@
  *   if yres_virtual > yres or xres_virtual > xres.
  *
  * int (*blank)( int blank_mode )
- *   Blank the screen if blank_mode != 0, else unblank. If NULL then blanking
- *   is done by setting the CLUT to black. Return != 0 if un-/blanking
- *   failed due to e.g. video mode which doesn't support it.
+ *   Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
+ *   the caller blanks by setting the CLUT to all black. Return 0 if blanking
+ *   succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
+ *   doesn't support it. Implements VESA suspend and powerdown modes on
+ *   hardware that supports disabling hsync/vsync:
+ *       blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
  */
 
 static struct fb_hwswitch {
@@ -529,6 +529,7 @@
 	int yres=var->yres;
 	int bpp=var->bits_per_pixel;
 	int linelen;
+	int yres_virtual = var->yres_virtual;
 
 	if (mono_moni) {
 		if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
@@ -582,14 +583,23 @@
 			bpp=1;
 		}
 	}
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
+		yres_virtual = yres;
 	if (var->sync & FB_SYNC_EXT)
 		par->hw.tt.sync=0;
 	else
 		par->hw.tt.sync=1;
 	linelen=xres*bpp/8;
-	if ((var->yoffset + yres)*linelen > screen_len && screen_len)
+	if (yres_virtual * linelen > screen_len && screen_len)
 		return -EINVAL;
-	par->screen_base=screen_base+ var->yoffset*linelen;
+	if (yres * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
+		return -EINVAL;
+	par->vyres = yres_virtual;
+	par->screen_base = screen_base + var->yoffset * linelen;
 	return 0;
 }
 
@@ -665,7 +675,11 @@
 	if (! use_hwscroll)
 		var->yres_virtual=var->yres;
 	else if (screen_len)
-		var->yres_virtual=screen_len/linelen;
+		if (par->vyres)
+			var->yres_virtual = par->vyres;
+		else
+			/* vyres==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
 	else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
@@ -784,17 +798,17 @@
 static struct pixel_clock {
 	unsigned long f;	/* f/[Hz] */
 	unsigned long t;	/* t/[ps] (=1/f) */
-	short right, hsync, left;	/* standard timing in clock cycles, not pixel */
+	int right, hsync, left;	/* standard timing in clock cycles, not pixel */
 		/* hsync initialized in falcon_detect() */
-	short sync_mask;	/* or-mask for hw.falcon.sync to set this clock */
-	short control_mask; /* ditto, for hw.falcon.vid_control */
+	int sync_mask;		/* or-mask for hw.falcon.sync to set this clock */
+	int control_mask;	/* ditto, for hw.falcon.vid_control */
 }
-f25  = {25175000, 39722, 18, 0, 42, 0x0, VCO_CLOCK25},
+f25  = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
 f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
 fext = {       0,     0, 18, 0, 42, 0x1, 0};
 
 /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
-static short vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
+static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
 
 /* Default hsync timing [mon_type] in picoseconds */
 static long h_syncs[4] = {3000000, 4700000, 4000000, 4700000};
@@ -817,22 +831,22 @@
 	fix->type = FB_TYPE_INTERLEAVED_PLANES;
 	fix->type_aux = 2;
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
 	if (par->hw.falcon.mono) {
 		fix->type = FB_TYPE_PACKED_PIXELS;
 		fix->type_aux = 0;
+		/* no smooth scrolling with longword aligned video mem */
+		fix->xpanstep = 32;
 	}
 	else if (par->hw.falcon.f_shift & 0x100) {
 		fix->type = FB_TYPE_PACKED_PIXELS;
 		fix->type_aux = 0;
-		fix->visual = FB_VISUAL_TRUECOLOR;  /* is this ok or should this be DIRECTCOLOR? */
+		/* Is this ok or should it be DIRECTCOLOR? */
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		fix->xpanstep = 2;
 	}
-	if (par->hw.falcon.mono)
-		/* no smooth scrolling possible with longword aligned video mem */
-		fix->xpanstep = 32;
-	else
-		fix->xpanstep = 1;
-	fix->ypanstep = 1;
-	fix->ywrapstep = 0;
 	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
 		fix->reserved[i]=0;
@@ -843,7 +857,6 @@
 static int falcon_decode_var( struct fb_var_screeninfo *var,
 							  struct atari_fb_par *par )
 {
-	int use_default_timing = 0;
 	int bpp = var->bits_per_pixel;
 	int xres = var->xres;
 	int yres = var->yres;
@@ -970,20 +983,22 @@
 		xres_virtual = (xres_virtual + 31) & ~31;
 	else
 		xres_virtual = (xres_virtual + 15) & ~15;
-	/* <=0 : yres_virtual determined by screensize */
-	if (yres_virtual < yres && yres_virtual > 0)
+
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
 		yres_virtual = yres;
 
+	/* backward bug-compatibility */
+	if (var->pixclock > 1)
+		var->pixclock -= 1;
+
 	par->hw.falcon.line_width = bpp * xres / 16;
 	par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
 
 	/* single or double pixel width */
 	xstretch = (xres == 320) ? 2 : 1;
 
-	/* Default values are used for vert./hor. timing if no pixelclock given. */
-	if (var->pixclock == 0)
-		use_default_timing = 1;
-
 #if 0 /* currently unused */
 	if (mon_type == F_MON_SM) {
 		if (xres != 640 && yres != 400)
@@ -1011,7 +1026,8 @@
 	{	/* F_MON_VGA */
 		if (bpp == 16)
 			xstretch = 2; /* hicolor only double pixel width */
-		if (use_default_timing) {
+		/* Default values are used for vert./hor. timing if no pixelclock given. */
+		if (var->pixclock == 0) {
 			int linesize;
 
 			/* Choose master pixelclock depending on hor. timing */
@@ -1035,37 +1051,28 @@
 			vsync_len = 3;
 		}
 		else {
-#if 0 /* TODO enable this (untested yet) */
-			/* Round down pixelclock */
-			int i; unsigned long pcl=0;
-			for (i=1; i<=4; i*=2) {
-				if (f25.t*i<=var->pixclock && pcl<f25.t*i) {
-					pcl=f25.t*i; pclock=&f25;
+			/* Choose largest pixelclock <= wanted clock */
+			int i;
+			unsigned long pcl = ULONG_MAX;
+			pclock = 0;
+			for (i=1; i <= 4; i *= 2) {
+				if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
+					pcl = f25.t * i;
+					pclock = &f25;
 				}
-				if (f32.t*i<=var->pixclock && pcl<f32.t*i) {
-					pcl=f32.t*i; pclock=&f32;
+				if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
+					pcl = f32.t * i;
+					pclock = &f32;
 				}
-				if (fext.t && fext.t*i<=var->pixclock && pcl<fext.t*i) {
-					pcl=fext.t*i; pclock=&fext;
+				if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
+					pcl = fext.t * i;
+					pclock = &fext;
 				}
 			}
-			if (!pcl)
+			if (!pclock)
 				return -EINVAL;
 			plen = pcl / pclock->t;
 
-#else
-			if (var->pixclock == f25.t || var->pixclock == 2*f25.t)
-				pclock = &f25;
-			else if (var->pixclock == f32.t || var->pixclock == 2*f32.t)
-				pclock = &f32;
-			else if ((var->pixclock == fext.t || var->pixclock == 2*fext.t) && fext.t) {
-				pclock = &fext;
-			}
-			else
-				return -EINVAL;
-			plen = var->pixclock / pclock->t;
-#endif
-
 			left_margin = var->left_margin;
 			right_margin = var->right_margin;
 			hsync_len = var->hsync_len;
@@ -1122,7 +1129,7 @@
 	/*********************
 	Horizontal timing: unit = [master clock cycles]
 	unit of hxx-registers: [master clock cycles * prescale]
-	Hxx-registers are 9-bit wide
+	Hxx-registers are 9 bit wide
 
 	1 line = ((hht + 2) * 2 * prescale) clock cycles
 
@@ -1209,7 +1216,7 @@
 	 * of the first displayed line!
 	 * One frame consists of VFT+1 half lines. VFT+1 must be even in
 	 * non-interlace, odd in interlace mode for synchronisation.
-	 * Vxx-registers are 11-bit wide
+	 * Vxx-registers are 11 bit wide
 	 */
 	par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
 	par->VDB = par->VBE;
@@ -1264,11 +1271,11 @@
 
   set_screen_base:
 	linelen = xres_virtual * bpp / 8;
-	if ((var->yoffset + yres)*linelen > screen_len && screen_len)
+	if (yres_virtual * linelen > screen_len && screen_len)
 		return -EINVAL;
-	if (var->yres_virtual * linelen > screen_len && screen_len)
+	if (yres * linelen > screen_len && screen_len)
 		return -EINVAL;
-	if (var->yres * linelen > screen_len && screen_len)
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
 		return -EINVAL;
 	par->vyres = yres_virtual;
 	par->screen_base = screen_base + var->yoffset * linelen;
@@ -1368,7 +1375,8 @@
 		if (par->vyres)
 			var->yres_virtual = par->vyres;
 		else
-			var->yres_virtual=screen_len/linelen;
+			/* vyres==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
 	else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
@@ -1499,7 +1507,7 @@
 }
 
 
-static void falcon_vbl_switcher( int irq, struct pt_regs *fp, void *dummy )
+static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
 {
 	struct falcon_hw *hw = &f_new_mode;
 
@@ -1529,8 +1537,6 @@
 		videl.vde = hw->vde;
 		videl.vss = hw->vss;
 
-		/*f030_sreg[2] = 0;*/
-
 		videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
 		if (hw->ste_mode) {
 			videl.st_shift = hw->st_shift; /* write enables STE palette */
@@ -1565,19 +1571,24 @@
 							   struct atari_fb_par *par )
 {
 	int xoffset;
+	int bpp = disp[currcon].var.bits_per_pixel;
 
-	if (disp[currcon].var.bits_per_pixel == 1)
+	if (bpp == 1)
 		var->xoffset = up(var->xoffset, 32);
-	par->hw.falcon.xoffset = var->xoffset & 15;
-	par->hw.falcon.line_offset = disp[currcon].var.bits_per_pixel *
-	       	  (disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16;
+	if (bpp != 16)
+		par->hw.falcon.xoffset = var->xoffset & 15;
+	else {
+		par->hw.falcon.xoffset = 0;
+		var->xoffset = up(var->xoffset, 2);
+	}
+	par->hw.falcon.line_offset = bpp *
+	       	(disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16;
 	if (par->hw.falcon.xoffset)
-		par->hw.falcon.line_offset -= disp[currcon].var.bits_per_pixel;
+		par->hw.falcon.line_offset -= bpp;
 	xoffset = var->xoffset - par->hw.falcon.xoffset;
 
-	par->screen_base
-		= screen_base + (var->yoffset * disp[currcon].var.xres_virtual +
-				xoffset) * disp[currcon].var.bits_per_pixel / 8;
+	par->screen_base = screen_base +
+	        (var->yoffset * disp[currcon].var.xres_virtual + xoffset) * bpp / 8;
 	if (fbhw->set_screen_base)
 		fbhw->set_screen_base (par->screen_base);
 	else
@@ -1629,24 +1640,37 @@
 {
 /* ++guenther: we can switch off graphics by changing VDB and VDE,
  * so VIDEL doesn't hog the bus while saving.
- * (this affects usleep()).
+ * (this may affect usleep()).
  */
+	int vdb, vss, hbe, hss;
+
 	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
 		return 1;
-	if (blank_mode) {
+
+	vdb = current_par.VDB;
+	vss = current_par.VSS;
+	hbe = current_par.HBE;
+	hss = current_par.HSS;
+
+	if (blank_mode >= 1) {
 		/* disable graphics output (this speeds up the CPU) ... */
-		videl.vdb = current_par.VFT + 1;
+		vdb = current_par.VFT + 1;
 		/* ... and blank all lines */
-		videl.hbe = current_par.HHT + 2;
-		/* VESA suspend mode, switch off HSYNC */
-		if (pwrsave && mon_type == F_MON_VGA)
-			videl.hss = current_par.HHT + 2;
+		hbe = current_par.HHT + 2;
 	}
-	else {
-		videl.vdb = current_par.VDB;
-		videl.hbe = current_par.HBE;
-		videl.hss = current_par.HSS;
+	/* use VESA suspend modes on VGA monitors */
+	if (mon_type == F_MON_VGA) {
+		if (blank_mode == 2 || blank_mode == 4)
+			vss = current_par.VFT + 1;
+		if (blank_mode == 3 || blank_mode == 4)
+			hss = current_par.HHT + 2;
 	}
+
+	videl.vdb = vdb;
+	videl.vss = vss;
+	videl.hbe = hbe;
+	videl.hss = hss;
+
 	return 0;
 }
 
@@ -1713,11 +1737,13 @@
 		fix->type_aux=0;
 		fix->visual=FB_VISUAL_MONO10;
 	}
-	fix->xpanstep = 0;
-	if (ATARIHW_PRESENT(EXTD_SHIFTER))
+	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
+		fix->xpanstep = 16;
 		fix->ypanstep = 1;
-	else
+	} else {
+		fix->xpanstep = 0;
 		fix->ypanstep = 0;
+	}
 	fix->ywrapstep = 0;
 	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
@@ -1733,6 +1759,7 @@
 	int yres=var->yres;
 	int bpp=var->bits_per_pixel;
 	int linelen;
+	int yres_virtual = var->yres_virtual;
 
 	if (mono_moni) {
 		if (bpp > 1 || xres > sttt_xres || yres > st_yres)
@@ -1763,13 +1790,22 @@
 		else
 			return -EINVAL;
 	}
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
+		yres_virtual = yres;
 	if (var->sync & FB_SYNC_EXT)
 		par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
 	else
 		par->hw.st.sync=(par->hw.st.sync & ~1);
 	linelen=xres*bpp/8;
-	if ((var->yoffset + yres)*linelen > screen_len && screen_len)
+	if (yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (yres * linelen > screen_len && screen_len)
 		return -EINVAL;
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
+		return -EINVAL;
+	par->vyres = yres_virtual;
 	par->screen_base=screen_base+ var->yoffset*linelen;
 	return 0;
 }
@@ -1827,7 +1863,11 @@
 	if (! use_hwscroll)
 		var->yres_virtual=var->yres;
 	else if (screen_len)
-		var->yres_virtual=screen_len/linelen;
+		if (par->vyres)
+			var->yres_virtual = par->vyres;
+		else
+			/* vyres==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
 	else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
@@ -2238,11 +2278,13 @@
 static int pan_display( struct fb_var_screeninfo *var,
                         struct atari_fb_par *par )
 {
-	if (var->xoffset)
+	if (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)
 		return -EINVAL;
-	par->screen_base
-		= screen_base + (var->yoffset * disp[currcon].var.xres_virtual
-						 * disp[currcon].var.bits_per_pixel / 8);
+	else
+		var->xoffset = up(var->xoffset, 16);
+	par->screen_base = screen_base +
+	        (var->yoffset * disp[currcon].var.xres_virtual + var->xoffset)
+	        * disp[currcon].var.bits_per_pixel / 8;
 	if (fbhw->set_screen_base)
 		fbhw->set_screen_base (par->screen_base);
 	else
@@ -2609,18 +2651,21 @@
 static int
 atari_fb_set_var(struct fb_var_screeninfo *var, int con)
 {
-	int err,oldxres,oldyres,oldbpp,oldxres_virtual,oldyoffset;
+	int err,oldxres,oldyres,oldbpp,oldxres_virtual,
+	    oldyres_virtual,oldyoffset;
 	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;
 		oldxres_virtual=disp[con].var.xres_virtual;
+		oldyres_virtual=disp[con].var.yres_virtual;
 		oldbpp=disp[con].var.bits_per_pixel;
 		oldyoffset=disp[con].var.yoffset;
 		disp[con].var=*var;
 		if (oldxres != var->xres || oldyres != var->yres 
 		    || oldxres_virtual != var->xres_virtual
+		    || oldyres_virtual != var->yres_virtual
 		    || oldbpp != var->bits_per_pixel
 		    || oldyoffset != var->yoffset) {
 			atari_fb_set_disp(con);
@@ -2778,6 +2823,13 @@
 	return 0;
 }
 
+/* (un)blank/poweroff
+ * 0 = unblank
+ * 1 = blank
+ * 2 = suspend vsync
+ * 3 = suspend hsync
+ * 4 = off
+ */
 static void
 atafb_blank(int blank)
 {
@@ -2828,8 +2880,8 @@
 #ifdef ATAFB_FALCON
 		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
 			fbhw = &falcon_switch;
-			add_isr(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, NULL,
-					"framebuffer/modeswitch");
+			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+			            "framebuffer/modeswitch", falcon_vbl_switcher);
 			break;
 		}
 #endif
@@ -2862,7 +2914,7 @@
 		real_screen_base=screen_base+ovsc_offset;
 		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
 		st_ovsc_switch(ovsc_switchmode);
-		if (m68k_is040or060) {
+		if (CPU_IS_040_OR_060) {
 			/* On a '040+, the cache mode of video RAM must be set to
 			 * write-through also for internal video hardware! */
 			cache_push( VTOP(screen_base), screen_len );
@@ -2979,12 +3031,10 @@
 	else if (!strncmp(this_opt,"internal:",9))
 		strcpy(int_str, this_opt+9);
 #ifdef ATAFB_FALCON
-	else if (!strcmp(this_opt, "pwrsave"))
-		pwrsave = 1;
 	else if (!strncmp(this_opt, "eclock:", 7)) {
 		fext.f = simple_strtoul(this_opt+7, NULL, 10);
 		/* external pixelclock in kHz --> ps */
-		fext.t = (2000000000UL/fext.f+1)/2;
+		fext.t = 1000000000/fext.f;
 		fext.f *= 1000;
 	}
 	else if (!strncmp(this_opt, "monitorcap:", 11))
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/ataints.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/atari/ataints.c	Wed Sep 25 10:47:38 1996
@@ -9,9 +9,9 @@
  *  about non-autovec ints yet. It hardcoded the number of possible ints to
  *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
  *  number of possible ints a constant defined in interrupt.h, which is
- *  47 for the Atari. So we can call add_isr() for all Atari interrupts just
- *  the normal way. Additionally, all vectors >= 48 are initialized to call
- *  trap() instead of inthandler(). This must be changed here, too.
+ *  47 for the Atari. So we can call request_irq() for all Atari interrupts
+ *  just the normal way. Additionally, all vectors >= 48 are initialized to
+ *  call trap() instead of inthandler(). This must be changed here, too.
  *
  * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>:
  *  Corrected a bug in atari_add_isr() which rejected all SCC
@@ -24,6 +24,11 @@
  *  Total rewrite of Atari interrupt handling, for new scheme see comments
  *  below.
  *
+ * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>:
+ *  Added new function atari_unregister_vme_int(), and
+ *  modified atari_register_vme_int() as well as IS_VALID_INTNO()
+ *  to work with it.
+ *
  * 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.
@@ -35,13 +40,13 @@
 #include <linux/ptrace.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 #include <asm/atari_stdma.h>
-#include <asm/bootinfo.h>
 #include <asm/irq.h>
 
 
@@ -74,14 +79,14 @@
  * The feature of more than one handler for one int source is still there, but
  * only applicable if all handers are of the same type. To not slow down
  * processing of ints with only one handler by the chaining feature, the list
- * calling function atari_call_isr_list() is only plugged in at the time the
+ * calling function atari_call_irq_list() is only plugged in at the time the
  * second handler is registered.
  *
  * Implementation notes: For fast-as-possible int handling, there are separate
  * entry points for each type (slow/fast/prio). The assembler handler calls
- * the isr directly in the usual case, no C wrapper is involved. In case of
- * multiple handlers, atari_call_isr_list() is registered as handler and calls
- * in turn the real isr's. To ease access from assembler level to the isr
+ * the irq directly in the usual case, no C wrapper is involved. In case of
+ * multiple handlers, atari_call_irq_list() is registered as handler and calls
+ * in turn the real irq's. To ease access from assembler level to the irq
  * function pointer and accompanying data, these two are stored in a separate
  * array, irq_handler[]. The rest of data (type, name) are put into a second
  * array, irq_param, that is accessed from C only. For each slow interrupt (32
@@ -106,17 +111,17 @@
 typedef void (*asm_irq_handler)(void);
 
 struct irqhandler {
-	isrfunc	isr;
-	void	*data;
+	void	(*handler)(int, void *, struct pt_regs *);
+	void	*dev_id;
 };
 
 struct irqparam {
-	int type;
-	char *name;
+	unsigned long	flags;
+	const char	*devname;
 };
 
 /*
- * Array with isr's and their parameter data. This array is accessed from low
+ * Array with irq's and their parameter data. This array is accessed from low
  * level assembler code, so an element size of 8 allows usage of index scaling
  * addressing mode.
  */
@@ -130,11 +135,11 @@
 static struct irqparam irq_param[NUM_INT_SOURCES];
 
 /*
- * Counter for next free interrupt vector number
+ * Bitmap for free interrupt vector numbers
  * (new vectors starting from 0x70 can be allocated by
  * atari_register_vme_int())
  */
-static int next_free_vme_vec = VME_SOURCE_BASE;
+static int free_vme_vec_bitmap = 0;
 
 /* check for valid int number (complex, sigh...) */
 #define	IS_VALID_INTNO(n)											\
@@ -147,8 +152,9 @@
 	  /* SCC ok if present and number even */						\
 	  ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE &&			\
 	   !((n) & 1) && ATARIHW_PRESENT(SCC)) ||						\
-	  /* greater numbers ok if less than #registered VME vectors */	\
-	  ((n) >= VME_SOURCE_BASE && (n) < next_free_vme_vec)))
+	  /* greater numbers ok if they are registered VME vectors */		\
+	  ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \
+		  free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE)))))
 
 
 /*
@@ -165,8 +171,7 @@
 #define SR "0x28"
 #define SAVE_ALL				\
 	"clrl	%%sp@-;"    /* stk_adj */	\
-	"clrl	%%sp@-;"			\
-	"subql	#1,%%sp@;"  /* orig d0 = -1 */	\
+	"pea	-1:w;"	    /* orig d0 = -1 */	\
 	"movel	%%d0,%%sp@-;" /* d0 */		\
 	"moveml	%%d1-%%d5/%%a0-%%a1,%%sp@-"
 
@@ -176,21 +181,19 @@
 void atari_slow_irq_##n##_dummy (void) {				   \
 __asm__ (ALIGN_STR "\n"							   \
 SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t"			   \
-	SAVE_ALL "\n"							   \
 "	addql	#1,"SYMBOL_NAME_STR(intr_count)"\n"			   \
+	SAVE_ALL "\n"							   \
 "	andb	#~(1<<(" #n "&7)),"	/* mask this interrupt */	   \
 	"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
-"	movew	%%sp@("SR"),%%d0\n"	/* get old IPL from stack frame */ \
+"	bfextu	%%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
 "	movew	%%sr,%%d1\n"						   \
-"	andw	#0x0700,%%d0\n"						   \
-"	andw	#0xf8ff,%%d1\n"						   \
-"	orw 	%%d0,%%d1\n"						   \
+"	bfins	%%d0,%%d1{#21,#3}\n"					   \
 "	movew	%%d1,%%sr\n"		/* set IPL = previous value */	   \
 "	addql	#1,%a0\n"						   \
 "	lea	"SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n"	   \
+"	pea 	%%sp@\n"		/* push addr of frame */	   \
 "	movel	%%a0@(4),%%sp@-\n"	/* push handler data */		   \
-"	pea 	%%sp@(4)\n"		/* push addr of frame */	   \
-"	pea 	(" #n "+8):w\n"		/* push int number */		   \
+"	pea 	(" #n "+0x10000008)\n"	/* push int number */		   \
 "	movel	%%a0@,%%a0\n"						   \
 "	jbsr	%%a0@\n"		/* call the handler */		   \
 "	addql	#8,%%sp\n"						   \
@@ -280,21 +283,21 @@
 __asm__ (ALIGN_STR "\n"
 SYMBOL_NAME_STR(atari_fast_irq_handler) ":
 	orw 	#0x700,%%sr		/* disable all interrupts */
-"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t"
+"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
+	addql	#1,"SYMBOL_NAME_STR(intr_count)"\n"
 	SAVE_ALL "
-	addql	#1,"SYMBOL_NAME_STR(intr_count)"
-	movew	%%sp@(" FORMATVEC "),%%d0	/* get vector number from stack frame */
-	andil	#0xfff,%%d0		/* mask off format nibble */
-	lsrl	#2,%%d0			/* convert vector to source */
-	subl	#(0x40-8),%%d0
+	/* get vector number from stack frame and convert to source */
+	bfextu	%%sp@(" FORMATVEC "){#4,#10},%%d0
+	subw	#(0x40-8),%%d0
 	jpl 	1f
-	addl	#(0x40-8-0x18),%%d0
+	addw	#(0x40-8-0x18),%%d0
 1:	lea	%a0,%%a0
 	addql	#1,%%a0@(%%d0:l:4)
 	lea	"SYMBOL_NAME_STR(irq_handler)",%%a0
 	lea	%%a0@(%%d0:l:8),%%a0
+	pea 	%%sp@			/* push frame address */
 	movel	%%a0@(4),%%sp@-		/* push handler data */
-	pea 	%%sp@(4)		/* push frame address */
+	bset	#28,%%d0		/* set MACHSPEC bit */
 	movel	%%d0,%%sp@-		/* push int number */
 	movel	%%a0@,%%a0
 	jsr	%%a0@			/* and call the handler */
@@ -313,12 +316,7 @@
 asm(".text\n"
 ALIGN_STR "\n"
 SYMBOL_NAME_STR(falcon_hblhandler) ":
-	movel	%d0,%sp@-
-	movew	%sp@(4),%d0
-	andw	#0xf8ff,%d0
-	orw	#0x0200,%d0	/* set saved ipl to 2 */
-	movew	%d0,%sp@(4)
-	movel	%sp@+,%d0
+	orw	#0x200,%sp@	/* set saved ipl to 2 */
 	rte");
 
 /* Defined in entry.S; only increments 'num_spurious' */
@@ -327,7 +325,7 @@
 extern void atari_microwire_cmd( int cmd );
 
 /*
- * void atari_init_INTS (void)
+ * void atari_init_IRQ (void)
  *
  * Parameters:	None
  *
@@ -337,7 +335,7 @@
  * the atari IRQ handling routines.
  */
 
-void atari_init_INTS(void)
+void atari_init_IRQ(void)
 {
 	int i;
 
@@ -353,9 +351,9 @@
 #else
 	mfp.vec_adr  = 0x40;	/* Automatic EOI-Mode */
 #endif
-	mfp.int_en_a =		    /* turn off MFP-Ints */
+	mfp.int_en_a = 0x00;	/* turn off MFP-Ints */
 	mfp.int_en_b = 0x00;
-	mfp.int_mk_a =			/* no Masking */
+	mfp.int_mk_a = 0xff;	/* no Masking */
 	mfp.int_mk_b = 0xff;
 
 	if (ATARIHW_PRESENT(TT_MFP)) {
@@ -364,9 +362,9 @@
 #else
 		tt_mfp.vec_adr  = 0x50;		/* Automatic EOI-Mode */
 #endif
-		tt_mfp.int_en_a =			/* turn off MFP-Ints */
+		tt_mfp.int_en_a = 0x00;		/* turn off MFP-Ints */
 		tt_mfp.int_en_b = 0x00;
-		tt_mfp.int_mk_a =			/* no Masking */
+		tt_mfp.int_mk_a = 0xff;		/* no Masking */
 		tt_mfp.int_mk_b = 0xff;
 	}
 
@@ -407,177 +405,169 @@
 }
 
 
-static void atari_call_isr_list( int irq, struct pt_regs *fp, void *_p )
+static void atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp )
 {
-  isr_node_t *p;
-	
-  for( p = (isr_node_t *)_p; p; p = p->next )
-    p->isr( irq, fp, p->data );
+	irq_node_t *node;
+
+	for (node = (irq_node_t *)dev_id; node; node = node->next)
+		node->handler(irq, node->dev_id, fp);
 }
 
 
 /*
- * atari_add_isr : add an interrupt service routine for a particular
- *		   machine specific interrupt source.
- *		   If the addition was successful, it returns 1, otherwise
- *		   it returns 0.  It will fail if the interrupt is already
- *                 occupied of another handler with different type
+ * atari_request_irq : add an interrupt service routine for a particular
+ *                     machine specific interrupt source.
+ *                     If the addition was successful, it returns 0.
  */
 
-int atari_add_isr(unsigned long source, isrfunc isr, int type, void
-		  *data, char *name)
+int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, const char *devname, void *dev_id)
 {
 	int vector;
 	
-	source &= ~IRQ_MACHSPEC;
-	if (type < IRQ_TYPE_SLOW || type > IRQ_TYPE_PRIO) {
-		printk ("atari_add_isr: Bad irq type %d requested from %s\n",
-				type, name );
-		return( 0 );
-	}
-	if (!IS_VALID_INTNO(source)) {
-		printk ("atari_add_isr: Unknown irq %ld requested from %s\n",
-				source, name );
-		return( 0 );
+	if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
+		printk ("%s: Bad irq type %ld requested from %s\n",
+		        __FUNCTION__, flags, devname);
+		return -EINVAL;
+	}
+	if (!IS_VALID_INTNO(irq)) {
+		printk ("%s: Unknown irq %d requested from %s\n",
+		        __FUNCTION__, irq, devname);
+		return -ENXIO;
 	}
-	vector = IRQ_SOURCE_TO_VECTOR(source);
+	vector = IRQ_SOURCE_TO_VECTOR(irq);
 
 	/*
 	 * Check type/source combination: slow ints are (currently)
 	 * only possible for MFP-interrupts.
 	 */
-	if (type == IRQ_TYPE_SLOW &&
-		(source < STMFP_SOURCE_BASE || source >= SCC_SOURCE_BASE)) {
-		printk ("atari_add_isr: Slow irq requested for non-MFP source %ld from %s\n",
-				source, name );
-		return( 0 );
+	if (flags == IRQ_TYPE_SLOW &&
+		(irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) {
+		printk ("%s: Slow irq requested for non-MFP source %d from %s\n",
+		        __FUNCTION__, irq, devname);
+		return -EINVAL;
 	}
 		
 	if (vectors[vector] == bad_interrupt) {
 		/* int has no handler yet */
-		irq_handler[source].isr = isr;
-		irq_handler[source].data = data;
-		irq_param[source].type = type;
-		irq_param[source].name = name;
+		irq_handler[irq].handler = handler;
+		irq_handler[irq].dev_id  = dev_id;
+		irq_param[irq].flags   = flags;
+		irq_param[irq].devname = devname;
 		vectors[vector] =
-			(type == IRQ_TYPE_SLOW) ? slow_handlers[source-STMFP_SOURCE_BASE] :
-			(type == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
-									  atari_prio_irq_handler;
+			(flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] :
+			(flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
+			                          atari_prio_irq_handler;
 		/* If MFP int, also enable and umask it */
-		atari_turnon_irq(source);
-		atari_enable_irq(source);
+		atari_turnon_irq(irq);
+		atari_enable_irq(irq);
 
-		return 1;
+		return 0;
 	}
-	else if (irq_param[source].type == type) {
+	else if (irq_param[irq].flags == flags) {
 		/* old handler is of same type -> handlers can be chained */
-		isr_node_t *p;
+		irq_node_t *node;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
 
-		if (irq_handler[source].isr != atari_call_isr_list) {
+		if (irq_handler[irq].handler != atari_call_irq_list) {
 			/* Only one handler yet, make a node for this first one */
-			p = new_isr_node();
-			if (p == NULL) return 0;
-			p->isr = irq_handler[source].isr;
-			p->data = irq_handler[source].data;
-			p->name = irq_param[source].name;
-			p->next = NULL;
-
-			irq_handler[source].isr = atari_call_isr_list;
-			irq_handler[source].data = p;
-			irq_param[source].name = "chained";
+			if (!(node = new_irq_node()))
+				return -ENOMEM;
+			node->handler = irq_handler[irq].handler;
+			node->dev_id  = irq_handler[irq].dev_id;
+			node->devname = irq_param[irq].devname;
+			node->next = NULL;
+
+			irq_handler[irq].handler = atari_call_irq_list;
+			irq_handler[irq].dev_id  = node;
+			irq_param[irq].devname   = "chained";
 		}
 
-		p = new_isr_node();
-		if (p == NULL) return 0;
-		p->isr = isr;
-		p->data = data;
-		p->name = name;
+		if (!(node = new_irq_node()))
+			return -ENOMEM;
+		node->handler = handler;
+		node->dev_id  = dev_id;
+		node->devname = devname;
 		/* new handlers are put in front of the queue */
-		p->next = irq_handler[source].data;
-		irq_handler[source].data = p;
+		node->next = irq_handler[irq].dev_id;
+		irq_handler[irq].dev_id = node;
 
 		restore_flags(flags);
-		return 1;
-	}
-	else {
-		printk ("atari_add_isr: Irq %ld allocated by other type int (call from %s)\n",
-				source, name );
-		return( 0 );
+		return 0;
+	} else {
+		printk ("%s: Irq %d allocated by other type int (call from %s)\n",
+		        __FUNCTION__, irq, devname);
+		return -EBUSY;
 	}
 }
 
-
-int atari_remove_isr(unsigned long source, isrfunc isr, void *data)
+void atari_free_irq(unsigned int irq, void *dev_id)
 {
 	unsigned long flags;
 	int vector;
-	isr_node_t **p, *q;
-
-	source &= ~IRQ_MACHSPEC;
+	irq_node_t **list, *node;
 
-	if (!IS_VALID_INTNO(source)) {
-		printk("atari_remove_isr: Unknown irq %ld\n", source);
-		return 0;
+	if (!IS_VALID_INTNO(irq)) {
+		printk("%s: Unknown irq %d\n", __FUNCTION__, irq);
+		return;
 	}
 
-	vector = IRQ_SOURCE_TO_VECTOR(source);
+	vector = IRQ_SOURCE_TO_VECTOR(irq);
 	if (vectors[vector] == bad_interrupt)
 		goto not_found;
 
 	save_flags(flags);
 	cli();
 
-	if (irq_handler[source].isr != atari_call_isr_list) {
+	if (irq_handler[irq].handler != atari_call_irq_list) {
 		/* It's the only handler for the interrupt */
-		if (irq_handler[source].isr != isr &&
-		    irq_handler[source].data != data) {
+		if (irq_handler[irq].dev_id != dev_id) {
 			restore_flags(flags);
 			goto not_found;
 		}
-		irq_handler[source].isr = NULL;
-		irq_handler[source].data = NULL;
-		irq_param[source].name = NULL;
+		irq_handler[irq].handler = NULL;
+		irq_handler[irq].dev_id  = NULL;
+		irq_param[irq].devname   = NULL;
 		vectors[vector] = bad_interrupt;
 		/* If MFP int, also disable it */
-		atari_disable_irq(source);
-		atari_turnoff_irq(source);
+		atari_disable_irq(irq);
+		atari_turnoff_irq(irq);
 
 		restore_flags(flags);
-		return 1;
+		return;
 	}
 
-	/* The interrupt is chained, find the isr on the list */
-	for( p = (isr_node_t **)&irq_handler[source].data; *p; p = &(*p)->next ) {
-		if ((*p)->isr == isr) break;
+	/* The interrupt is chained, find the irq on the list */
+	for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) {
+		if ((*list)->dev_id == dev_id) break;
 	}
-	if (!*p) {
+	if (!*list) {
 		restore_flags(flags);
 		goto not_found;
 	}
 
-	(*p)->isr = NULL; /* Mark it as free for reallocation */
-	*p = (*p)->next;
+	(*list)->handler = NULL; /* Mark it as free for reallocation */
+	*list = (*list)->next;
 
 	/* If there's now only one handler, unchain the interrupt, i.e. plug in
-	 * the handler directly again and omit atari_call_isr_list */
-	q = (isr_node_t *)irq_handler[source].data;
-	if (q && !q->next) {
-		irq_handler[source].isr = q->isr;
-		irq_handler[source].data = q->data;
-		irq_param[source].name = q->name;
-		q->isr = NULL; /* Mark it as free for reallocation */
+	 * the handler directly again and omit atari_call_irq_list */
+	node = (irq_node_t *)irq_handler[irq].dev_id;
+	if (node && !node->next) {
+		irq_handler[irq].handler = node->handler;
+		irq_handler[irq].dev_id  = node->dev_id;
+		irq_param[irq].devname   = node->devname;
+		node->handler = NULL; /* Mark it as free for reallocation */
 	}
 
 	restore_flags(flags);
-	return 1;
+	return;
 
-  not_found:
-	printk("atari_remove_isr: isr %p not found on list!\n", isr);
-	return 0;
+not_found:
+	printk("%s: tried to remove invalid irq\n", __FUNCTION__);
+	return;
 }
 
 
@@ -588,46 +578,60 @@
 
 unsigned long atari_register_vme_int(void)
 {
-	unsigned long source;
+	int i;
+
+	for(i = 0; i < 32; i++)
+		if((free_vme_vec_bitmap & (1 << i)) == 0)
+			break;
 	
-	if (next_free_vme_vec == NUM_ATARI_SOURCES)
+	if(i == 16)
 		return 0;
 
-	source = next_free_vme_vec | IRQ_MACHSPEC;
-	next_free_vme_vec++;
-	return source;
+	free_vme_vec_bitmap |= 1 << i;
+	return (VME_SOURCE_BASE + i) | IRQ_MACHSPEC;
 }
 
 
-int atari_get_irq_list(char *buf, int len)
+void atari_unregister_vme_int(unsigned long irq)
 {
-	int i;
+	irq &= ~IRQ_MACHSPEC;
+	
+	if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+		irq -= VME_SOURCE_BASE;
+		free_vme_vec_bitmap &= ~(1 << irq);
+	}
+}
+
+
+int atari_get_irq_list(char *buf)
+{
+	int i, len = 0;
 
 	for (i = 0; i < NUM_INT_SOURCES; ++i) {
 		if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
 			continue;
 		if (i < STMFP_SOURCE_BASE)
-			len += sprintf(buf+len, "auto %2d: %8d ",
+			len += sprintf(buf+len, "auto %2d: %10u ",
 				       i, kstat.interrupts[i]);
 		else
-			len += sprintf(buf+len, "vec $%02x: %8d ",
+			len += sprintf(buf+len, "vec $%02x: %10u ",
 				       IRQ_SOURCE_TO_VECTOR(i),
 				       kstat.interrupts[i]);
 
-		if (irq_handler[i].isr != atari_call_isr_list) {
-			len += sprintf(buf+len, "%s\n", irq_param[i].name);
+		if (irq_handler[i].handler != atari_call_irq_list) {
+			len += sprintf(buf+len, "%s\n", irq_param[i].devname);
 		}
 		else {
-			isr_node_t *p;
-			for( p = (isr_node_t *)irq_handler[i].data; p; p = p->next ) {
-				len += sprintf(buf+len, "%s\n", p->name);
+			irq_node_t *p;
+			for( p = (irq_node_t *)irq_handler[i].dev_id; p; p = p->next ) {
+				len += sprintf(buf+len, "%s\n", p->devname);
 				if (p->next)
 					len += sprintf( buf+len, "                  " );
 			}
 		}
 	}
 	if (num_spurious)
-		len += sprintf(buf+len, "spurio.: %8ld\n", num_spurious);
+		len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
 	
 	return len;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/atakeyb.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/atari/atakeyb.c	Wed Sep 25 10:47:38 1996
@@ -29,10 +29,9 @@
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
-extern int do_poke_blanked_console;
-extern void process_keycode (int);
+extern void handle_scancode(unsigned char);
 extern int ovsc_switchmode;
-unsigned char mach_keyboard_type;
+extern unsigned char mach_keyboard_type;
 static void atakeyb_rep( unsigned long ignore );
 extern unsigned int keymap_count;
 
@@ -41,7 +40,6 @@
 /* Hook for mouse driver */
 void (*atari_mouse_interrupt_hook) (char *);
 
-#define ATAKEY_CAPS	(58)
 #define BREAK_MASK	(0x80)
 
 /*
@@ -83,6 +81,11 @@
  *      Alt + Down       -> Scroll forward console (if implemented)
  *      Alt + CapsLock   -> NumLock
  *
+ * ++Andreas:
+ *
+ *  - Help mapped to K_HELP
+ *  - Undo mapped to K_UNDO (= K_F246)
+ *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
  */
 
 static u_short ataplain_map[NR_KEYS] = {
@@ -98,7 +101,7 @@
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf121, 0xf11b, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -117,7 +120,7 @@
 	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf119, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf205, 0xf203, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf205, 0xf203, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -136,7 +139,7 @@
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -155,7 +158,7 @@
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -174,7 +177,7 @@
 	0xf20b, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf20a, 0xf200, 0xf209, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf206, 0xf204, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf907,
+	0xf200, 0xf206, 0xf204, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf907,
 	0xf908, 0xf909, 0xf904, 0xf905, 0xf906, 0xf901, 0xf902, 0xf903,
 	0xf900, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -193,7 +196,7 @@
 	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -212,7 +215,7 @@
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -231,7 +234,7 @@
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -270,7 +273,7 @@
 {
 	pt_regs = NULL;
 
-	/* Disable keyboard it for the time we call process_keycode(), else a race
+	/* Disable keyboard for the time we call handle_scancode(), else a race
 	 * in the keyboard tty queue may happen */
 	atari_disable_irq( IRQ_MFP_ACIA );
 	del_timer( &atakeyb_rep_timer );
@@ -282,7 +285,7 @@
 		atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
 		add_timer( &atakeyb_rep_timer );
 
-		process_keycode (rep_scancode);
+		handle_scancode(rep_scancode);
 	}
 
 	atari_enable_irq( IRQ_MFP_ACIA );
@@ -306,7 +309,7 @@
  * because then the keyboard repeat strikes...
  */
 
-static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
+static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
   u_char acia_stat;
   int scancode;
@@ -335,7 +338,7 @@
 	rep_scancode = 0;
 	if (IS_SYNC_CODE(scancode)) {
 	    /* This code seem already to be the start of a new packet or a
-	     * single keycode */
+	     * single scancode */
 	    kb_state.state = KEYBOARD;
 	    goto interpret_scancode;
 	}
@@ -350,6 +353,7 @@
     if (acia_stat & ACIA_RDRF)	/* received a character */
     {
 	scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
+	mark_bh(KEYBOARD_BH);
       interpret_scancode:
 	switch (kb_state.state)
 	{
@@ -398,11 +402,7 @@
 		    add_timer( &atakeyb_rep_timer );
 		}
 
-		process_keycode( break_flag | scancode );
-		do_poke_blanked_console = 1;
-		mark_bh(CONSOLE_BH);
-		add_keyboard_randomness(scancode);
-
+		handle_scancode(break_flag | scancode);
 		break;
 	    }
 	    break;
@@ -482,7 +482,7 @@
 	printk("Error in keyboard communication\n");
     }
 
-    /* process_keycode() can take a lot of time, so check again if
+    /* handle_scancode() can take a lot of time, so check again if
 	 * some character arrived
 	 */
     goto repeat;
@@ -775,8 +775,8 @@
     kb_state.state = KEYBOARD;
     kb_state.len = 0;
 
-    add_isr(IRQ_MFP_ACIA, keyboard_interrupt, IRQ_TYPE_SLOW, NULL,
-	    "keyboard/mouse/MIDI");
+    request_irq(IRQ_MFP_ACIA, keyboard_interrupt, IRQ_TYPE_SLOW,
+                "keyboard/mouse/MIDI", keyboard_interrupt);
 
     atari_turnoff_irq(IRQ_MFP_ACIA);
     do {
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/atari.mup linux/arch/m68k/atari/atari.mup
--- lx2.0/v2.0.21/linux/arch/m68k/atari/atari.mup	Wed Dec 27 22:44:02 1995
+++ linux/arch/m68k/atari/atari.mup	Thu Jan  1 02:00:00 1970
@@ -1,16 +0,0 @@
-gcc -D__KERNEL__ -O2 -m68030 -c atacon.c -o atacon.o
-gcc -D__KERNEL__ -O2 -m68030 -c atasound.c -o atasound.o
-gcc -D__KERNEL__ -O2 -m68030 -c ataints.c -o ataints.o
-gcc -D__KERNEL__ -O2 -m68030 -c atapart.c -o atapart.o
-gcc -D__KERNEL__ -O2 -m68030 -c atakeyb.c -o atakeyb.o
-gcc -D__KERNEL__ -O2 -m68030 -c joystick.c -o joystick.o
-gcc -D__KERNEL__ -O2 -m68030 -c mouse.c -o mouse.o
-gcc -D__KERNEL__ -O2 -m68030 -c config.c -o config.o
-gcc -D__KERNEL__ -O2 -m68030 -c font_8x16.c -o font_8x16.o
-gcc -D__KERNEL__ -O2 -m68030 -c font_8x8.c -o font_8x8.o
-gcc -D__KERNEL__ -O2 -m68030 -c stdma.c -o stdma.o
-
-
-lnx-ld -r -o atari.o atacon.o atasound.o ataints.o atapart.o atakeyb.o config.o font_8x8.o font_8x1.o joystick.o mouse.o stdma.o
-
-cp atari.o ..\makedir
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/atasound.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/atari/atasound.c	Wed Sep 25 10:47:38 1996
@@ -17,17 +17,16 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/major.h>
-#include <linux/config.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 
+#include <asm/setup.h>
 #include <asm/atarihw.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/atariints.h>
-#include <asm/bootinfo.h>
 
 
 /*
@@ -119,10 +118,10 @@
 	}
 	else {
 
-		/* convert from PC counter value (base frequency 1.193 MHz)
+		/* convert from frequency value
 		 * to PSG period value (base frequency 125 kHz).
 		 */
-		int period = (PSG_FREQ * count + PC_FREQ/2) / PC_FREQ;
+		int period = PSG_FREQ / count;
 
 		if (period > 0xfff) period = 0xfff;
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/config.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/atari/config.c	Wed Sep 25 10:47:38 1996
@@ -1,7 +1,7 @@
 /*
- *  linux/atari/config.c
+ *  linux/arch/m68k/atari/config.c
  *
- *  Copyright (C) 1994 Bj”rn Brauel
+ *  Copyright (C) 1994 Bjoern Brauel
  *
  *  5/2/94 Roman Hodek:
  *    Added setting of time_adj to get a better clock.
@@ -27,12 +27,13 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <asm/bootinfo.h>
 #include <linux/mc146818rtc.h>
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/interrupt.h>
 
+#include <asm/setup.h>
 #include <asm/atarihw.h>
 #include <asm/atarihdreg.h>
 #include <asm/atariints.h>
@@ -43,16 +44,20 @@
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 
-extern void atari_sched_init(isrfunc);
+extern void atari_sched_init(void (*)(int, void *, struct pt_regs *));
+/* atari specific keyboard functions */
 extern int atari_keyb_init(void);
 extern int atari_kbdrate (struct kbd_repeat *);
 extern void atari_kbd_leds (unsigned int);
-extern void atari_init_INTS (void);
-extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
-extern int atari_remove_isr (unsigned long, isrfunc, void *);
-extern void atari_enable_irq (unsigned);
-extern void atari_disable_irq (unsigned);
-extern int atari_get_irq_list (char *buf, int len);
+/* atari specific irq functions */
+extern void atari_init_IRQ (void);
+extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                              unsigned long flags, const char *devname, void *dev_id);
+extern int atari_free_irq (unsigned int irq, void *dev_id);
+extern void atari_enable_irq (unsigned int);
+extern void atari_disable_irq (unsigned int);
+extern int atari_get_irq_list (char *buf);
+/* atari specific timer functions */
 extern unsigned long atari_gettimeoffset (void);
 extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
 extern void atari_gettod (int *, int *, int *, int *, int *, int *);
@@ -206,9 +211,9 @@
     mach_keyb_init       = atari_keyb_init;
     mach_kbdrate         = atari_kbdrate;
     mach_kbd_leds        = atari_kbd_leds;
-    mach_init_INTS       = atari_init_INTS;
-    mach_add_isr         = atari_add_isr;
-    mach_remove_isr      = atari_remove_isr;
+    mach_init_IRQ        = atari_init_IRQ;
+    mach_request_irq     = atari_request_irq;
+    mach_free_irq        = atari_free_irq;
     mach_enable_irq      = atari_enable_irq;
     mach_disable_irq     = atari_disable_irq;
     mach_get_irq_list	 = atari_get_irq_list;
@@ -380,7 +385,7 @@
     }
     printk("\n");
 
-    if (m68k_is040or060)
+    if (CPU_IS_040_OR_060)
         /* Now it seems to be safe to turn of the tt0 transparent
          * translation (the one that must not be turned off in
          * head.S...)
@@ -406,7 +411,7 @@
      * design of the bus.
      */
 
-    if (!m68k_is040or060) {
+    if (CPU_IS_020_OR_030) {
         unsigned long	tt1_val;
         tt1_val = 0xfe008543;	/* Translate 0xfexxxxxx, enable, cache
                                  * inhibit, read and write, FDC mask = 3,
@@ -427,14 +432,15 @@
     }
 }
 
-void atari_sched_init (isrfunc timer_routine)
+void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
 {
     /* set Timer C data Register */
     mfp.tim_dt_c = INT_TICKS;
     /* start timer C, div = 1:100 */
     mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; 
     /* install interrupt service routine for MFP Timer C */
-    add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
+    request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
+                "timer", timer_routine);
 }
 
 /* ++andreas: gettimeoffset fixed to check for pending interrupt */
@@ -1031,9 +1037,9 @@
 	 "movec	%/d0,%/vbr"
 	 : : : "d0" );
     
-    if (m68k_is040or060) {
+    if (CPU_IS_040_OR_060) {
         unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
-	if (m68k_is040or060 == 6) {
+	if (CPU_IS_060) {
 	    /* 68060: clear PCR to turn off superscalar operation */
 	    __asm__ __volatile__
 		("moveq	#0,%/d0\n\t"
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/ksyms.c linux/arch/m68k/atari/ksyms.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/ksyms.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/atari/ksyms.c	Wed Sep 25 10:47:38 1996
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
@@ -13,6 +12,7 @@
 
 	X(is_medusa),
 	X(atari_register_vme_int),
+	X(atari_unregister_vme_int),
 	X(stdma_lock),
 	X(stdma_release),
 	X(stdma_others_waiting),
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/stdma.c	Sun Sep  8 19:50:20 1996
+++ linux/arch/m68k/atari/stdma.c	Wed Sep 25 10:47:38 1996
@@ -32,7 +32,7 @@
 #include <linux/types.h>
 #include <linux/genhd.h>
 #include <linux/sched.h>
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/atari_stdma.h>
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
@@ -41,7 +41,8 @@
 #include <asm/irq.h>
 
 static int stdma_locked = 0;			/* the semaphore */
-static isrfunc	stdma_isr = NULL;		/* int func to be called */
+						/* int func to be called */
+static void (*stdma_isr)(int, void *, struct pt_regs *) = NULL;
 static void	*stdma_isr_data = NULL;		/* data passed to isr */
 static struct wait_queue *stdma_wait = NULL;	/* wait queue for ST-DMA */
 
@@ -50,7 +51,7 @@
 
 /***************************** Prototypes *****************************/
 
-static void stdma_int (int irq, struct pt_regs *fp, void *dummy);
+static void stdma_int (int irq, void *dummy, struct pt_regs *fp);
 
 /************************* End of Prototypes **************************/
 
@@ -72,7 +73,7 @@
  *
  */
 
-void stdma_lock(isrfunc isr, void *data)
+void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
 {
 	unsigned long	oldflags;
 
@@ -86,7 +87,7 @@
 		sleep_on(&stdma_wait);
 
 	stdma_locked   = 1;
-	stdma_isr      = isr;
+	stdma_isr      = handler;
 	stdma_isr_data = data;
 	restore_flags(oldflags);
 }
@@ -174,8 +175,8 @@
 void stdma_init(void)
 {
 	stdma_isr = NULL;
-	add_isr(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, NULL,
-		"ST-DMA: floppy/ACSI/IDE/Falcon-SCSI");
+	request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
+	            "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int);
 }
 
 
@@ -187,8 +188,8 @@
  *
  */
 
-static void stdma_int(int irq, struct pt_regs *fp, void *dummy)
+static void stdma_int(int irq, void *dummy, struct pt_regs *fp)
 {
   if (stdma_isr)
-      (*stdma_isr)(irq, fp, stdma_isr_data);
+      (*stdma_isr)(irq, stdma_isr_data, fp);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- lx2.0/v2.0.21/linux/arch/m68k/atari/stram.c	Wed Dec 27 22:44:28 1995
+++ linux/arch/m68k/atari/stram.c	Wed Sep 25 10:47:38 1996
@@ -2,7 +2,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/atarihw.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/Makefile linux/arch/m68k/boot/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/boot/Makefile	Wed Dec 27 22:44:28 1995
+++ linux/arch/m68k/boot/Makefile	Wed Sep 25 10:47:38 1996
@@ -6,32 +6,57 @@
 # for more details.
 
 ifdef CONFIG_AMIGA
-AMIGA_BOOTOBJS := amiga/bootstrap.o
+AMIGA_BOOTSTRAP = amiga_bootstrap
+AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
+AMIGA_HOSTCC = m68k-cbm-amigados-gcc -I$(TOPDIR)/include
+AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
 endif
 
 ifdef CONFIG_ATARI
+ATARI_BOOTSTRAP = atari_bootstrap
 ATARI_BOOTOBJS := atari/bootstrap.o
-HOSTCC += -b m68k-mint
+ATARI_HOSTCC = m68k-mint-gcc -I$(TOPDIR)/include
+ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
+
+# BOOTP/TFTP support in bootstrap?
+# USE_BOOTP = y
+
+ifdef USE_BOOTP
+ATARI_BOOTOBJS += atari/bootp.o
+ATARI_HOSTFLAGS += -DUSE_BOOTP
+
+# low-level Ethernet drivers:
+
+# Lance (RieblCard, PAM-VME)
+ATARI_BOOTOBJS += atari/ethlance.o
+ATARI_HOSTFLAGS += -DETHLL_LANCE
+
+endif
 endif
 
 ifdef CONFIG_ATARI
 atari_bootstrap: $(ATARI_BOOTOBJS)
-	$(HOSTCC) $(HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
+	$(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
 	rm -f ../../../bootstrap
 	ln $@ ../../../bootstrap
 endif
 
 ifdef CONFIG_AMIGA
 amiga_bootstrap: $(AMIGA_BOOTOBJS)
-	$(HOSTCC) $(HOSTFLAGS) -o $@ $(AMIGA_BOOTOBJS)
+	$(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
 	rm -f ../../../bootstrap
 	ln $@ ../../../bootstrap
 endif
 
-$(AMIGA_BOOTOBJS) $(ATARI_BOOTOBJS): %.o: %.c
-	$(HOSTCC) $(HOSTFLAGS) -c $< -o $@
+$(AMIGA_BOOTOBJS): %.o: %.c
+	$(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -c $< -o $@
+
+$(ATARI_BOOTOBJS): %.o: %.c
+	$(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -c $< -o $@
+
+bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
 
 clean:
-	rm -f *.o
+	rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap
 
 dep:
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c
--- lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/bootstrap.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/boot/amiga/bootstrap.c	Wed Sep 25 10:47:38 1996
@@ -1,18 +1,26 @@
 /*
-** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga
-**                and and launches it.
+** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
+**					     kernel into an Amiga and launches
+**					     it.
 **
 ** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
 **
 ** Modified 11-May-94 by Geert Uytterhoeven
-**                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
 **     - A3640 MapROM check
 ** Modified 31-May-94 by Geert Uytterhoeven
 **     - Memory thrash problem solved
 ** Modified 07-March-95 by Geert Uytterhoeven
 **     - Memory block sizes are rounded to a multiple of 256K instead of 1M
-**       This _requires_ >0.9pl5 to work!
-**       (unless all block sizes are multiples of 1M :-)
+**	 This _requires_ >0.9pl5 to work!
+**	 (unless all block sizes are multiples of 1M :-)
+** Modified 11-July-95 by Andreas Schwab
+**     - Support for ELF kernel (untested!)
+** Modified 10-Jan-96 by Geert Uytterhoeven
+**     - The real Linux/m68k boot code moved to linuxboot.[ch]
+** Modified 9-Sep-96 by Geert Uytterhoeven
+**     - Rewritten option parsing
+**     - New parameter passing to linuxboot() (linuxboot_args)
 **
 ** 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
@@ -23,760 +31,303 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <string.h>
 #include <sys/file.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-/* Amiga bootstrap include file */
-#include "bootstrap.h"
-
-/* required Linux/68k include files */
+/* required Linux/m68k include files */
 #include <linux/a.out.h>
-#include <asm/bootinfo.h>
-
-/* temporary stack size */
-#define TEMP_STACKSIZE	256
-
-/* Exec Base */
-extern struct ExecBase *SysBase;
-
-extern char *optarg;
-
-struct exec kexec;
-char *memptr;
-u_long start_mem;
-u_long mem_size;
-u_long rd_size;
-
-struct ExpansionBase *ExpansionBase;
-struct GfxBase *GfxBase;
-
-struct bootinfo bi;
-u_long bi_size = sizeof bi;
-
-caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
-
-void usage(void)
-{
-	fprintf (stderr, "Usage:\n"
-		 "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
-		 " [option...]\n");
-	exit (EXIT_FAILURE);
-}
-
-/*
- * This assembler code is copied to chip ram, and
- * then executed.
- * It copies the kernel (and ramdisk) to their
- * final resting place.
- */
-#ifndef __GNUC__
-#error GNU CC is required to compile the bootstrap program
-#endif
-asm("
-.text
-.globl _copyall, _copyallend
-_copyall:
-				| /* put variables in registers because they may */
-	lea	_kexec,a3	| /* be overwritten by kernel/ramdisk copy!! - G.U. */
-	movel	_memptr,a4
-	movel	_start_mem,a5
-	movel	_mem_size,d0
-	movel	_rd_size,d1
-	movel	_bi_size,d5
-	movel	a3@(4),d2	| kexec.a_text
-	movel	a3@(8),d3	| kexec.a_data
-	movel	a3@(12),d4	| kexec.a_bss
-
-				| /* copy kernel text and data */
-	movel	a4,a0		| src = (u_long *)memptr;
-	movel	a0,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
-	addl	d2,a2
-	addl	d3,a2
-	movel	a5,a1		| dest = (u_long *)start_mem;
-1:	cmpl	a0,a2
-	beqs	2f		| while (src < limit)
-	moveb	a0@+,a1@+	|	*dest++ = *src++;
-	bras	1b
-2:
-
-				| /* clear kernel bss */
-	movel	a1,a0		| dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data);
-	movel	a1,a2		| limit = dest + kexec.a_bss / sizeof(u_long);
-	addl	d4,a2
-1:	cmpl	a0,a2
-	beqs	2f		| while (dest < limit)
-	clrb	a0@+		|	*dest++ = 0;
-	bras	1b
-2:
-
-				| /* copy bootinfo to end of bss */
-	movel	a4,a1		| src = (u long *)memptr + kexec.a_text + kexec.a_data);
-	addl	d2,a1
-	addl	d3,a1		| dest = end of bss (already in a0)
-	movel   d5,d7		| count = sizeof bi
-	subql	#1,d7
-1:	moveb	a1@+,a0@+	| while (--count > -1)
-	dbra	d7,1b		|	*dest++ = *src++
-	
-
-				| /* copy the ramdisk to the top of memory (from back to front) */
-	movel	a5,a1		| dest = (u_long *)(start_mem + mem_size);
-	addl	d0,a1
-	movel	a4,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data + sizeof bi);
-	addl	d2,a2
-	addl	d3,a2
-        addl    d5,a2
-	movel	a2,a0		| src = (u_long *)((u_long)limit + rd_size);
-	addl	d1,a0
-1:	cmpl	a0,a2
-	beqs	2f		| while (src > limit)
-	moveb	a0@-,a1@-	| 	*--dest = *--src;
-	bras	1b
-2:
-				| /* jump to start of kernel */
-	movel	a5,a0		| jump_to (START_MEM);
-	jsr	a0@
-_copyallend:
-");
-
-asm("
-.text
-.globl _maprommed
-_maprommed:
-	oriw	#0x0700,sr
-	moveml	#0x3f20,sp@-
-/* Save cache settings */
-	.long 	0x4e7a1002	/* movec cacr,d1 */
-/* Save MMU settings */
-	.long 	0x4e7a2003	/* movec tc,d2 */
-	.long 	0x4e7a3004	/* movec itt0,d3 */
-	.long 	0x4e7a4005	/* movec itt1,d4 */
-	.long 	0x4e7a5006	/* movec dtt0,d5 */
-	.long 	0x4e7a6007	/* movec dtt1,d6 */
-	moveq	#0,d0
-	movel	d0,a2
-/* Disable caches */
-	.long 	0x4e7b0002	/* movec d0,cacr */
-/* Disable MMU */
-	.long 	0x4e7b0003	/* movec d0,tc */
-	.long 	0x4e7b0004	/* movec d0,itt0 */
-	.long 	0x4e7b0005	/* movec d0,itt1 */
-	.long 	0x4e7b0006	/* movec d0,dtt0 */
-	.long 	0x4e7b0007	/* movec d0,dtt1 */
-	lea	0x07f80000,a0
-	lea	0x00f80000,a1
-	movel	a0@,d7
-	cmpl	a1@,d7
-	jnes	1f
-	movel	d7,d0
-	notl	d0
-	movel	d0,a0@
-	nop
-	cmpl	a1@,d0
-	jnes	1f
-/* MapROMmed A3640 present */
-	moveq	#-1,d0
-	movel	d0,a2
-1:	movel	d7,a0@
-/* Restore MMU settings */
-	.long 	0x4e7b2003	/* movec d2,tc */
-	.long 	0x4e7b3004	/* movec d3,itt0 */
-	.long 	0x4e7b4005	/* movec d4,itt1 */
-	.long 	0x4e7b5006	/* movec d5,dtt0 */
-	.long 	0x4e7b6007	/* movec d6,dtt1 */
-/* Restore cache settings */
-	.long 	0x4e7b1002	/* movec d1,cacr */
-	movel	a2,d0
-	moveml	sp@+,#0x04fc
-	rte
-");
-
-extern unsigned long maprommed();
+#include <linux/elf.h>
+#include <asm/setup.h>
+#include <asm/page.h>
 
+/* Amiga bootstrap include files */
+#include "linuxboot.h"
+#include "bootstrap.h"
 
-extern char copyall, copyallend;
-
-int main(int argc, char *argv[])
-{
-	int ch, debugflag = 0, kfd, rfd = -1, i;
-	long fast_total = 0;	     /* total Fast RAM in system */
-	struct MemHeader *mnp;
-	struct ConfigDev *cdp = NULL;
-	char *kernel_name = "vmlinux";
-	char *ramdisk_name = NULL;
-	char *memfile = NULL;
-	u_long memreq;
-	void (*startfunc)(void);
-	long startcodesize;
-	u_long *stack, text_offset;
-	unsigned char *rb3_reg = NULL, *piccolo_reg = NULL, *sd64_reg = NULL;
-
-	/* print the greet message */
-	puts("Linux/68k Amiga Bootstrap version 1.11");
-	puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
-
-	/* machine is Amiga */
-	bi.machtype = MACH_AMIGA;
-
-	/* check arguments */
-	while ((ch = getopt(argc, argv, "dk:r:m:")) != EOF)
-		switch (ch) {
-		    case 'd':
-			debugflag = 1;
-			break;
-		    case 'k':
-			kernel_name = optarg;
-			break;
-		    case 'r':
-			ramdisk_name = optarg;
-			break;
-		    case 'm':
-			memfile = optarg;
-			break;
-		    case '?':
-		    default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	SysBase = *(struct ExecBase **)4;
-
-	/* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
-	/* open Expansion Library */
-	ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 36);
-	if (!ExpansionBase) {
-		puts("Unable to open expansion.library V36 or greater!  Aborting...");
-		exit(EXIT_FAILURE);
-	}
-
-	/* find all of the autoconfig boards in the system */
-	cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
-	for (i=0; (i < NUM_AUTO) && cdp; i++) {
-		/* copy the contents of each structure into our boot info */
-		memcpy(&bi.bi_amiga.autocon[i], cdp, sizeof(struct ConfigDev));
 
-		/* count this device */
-		bi.bi_amiga.num_autocon++;
+/* Library Bases */
+extern const struct ExecBase *SysBase;
+const struct ExpansionBase *ExpansionBase;
+const struct GfxBase *GfxBase;
 
-		/* get next device */
-		cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
-	}
+static const char *memfile_name = NULL;
 
-	/* find out the memory in the system */
-	for (mnp = (struct MemHeader *)SysBase->MemList.l_head;
-	     (bi.num_memory < NUM_MEMINFO) && mnp->mh_Node.ln_Succ;
-	     mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ)
-	{
-		struct MemHeader mh;
-
-		/* copy the information */
-		mh = *mnp;
-
-		/* if we suspect that Kickstart is shadowed in an A3000,
-		   modify the entry to show 512K more at the top of RAM
-		   Check first for a MapROMmed A3640 board: overwriting the
-		   Kickstart image causes an infinite lock-up on reboot! */
-
-		if (mh.mh_Upper == (void *)0x07f80000)
-			if ((SysBase->AttnFlags & AFF_68040) && Supervisor(maprommed))
-				printf("A3640 MapROM detected.\n");
-			else {
-				mh.mh_Upper = (void *)0x08000000;
-				printf("A3000 shadowed Kickstart detected.\n");
-			}
-
-		/* if we suspect that Kickstart is zkicked,
-		   modify the entry to show 512K more at the bottom of RAM */
-		if (mh.mh_Lower == (void *)0x00280020) {
-		    mh.mh_Lower =  (void *)0x00200000;
-		    printf("ZKick detected.\n");
-		}
-
-		/*
-		 * If this machine has "LOCAL" memory between 0x07000000
-		 * and 0x080000000, then we'll call it an A3000.
-		 */
-		if (mh.mh_Lower >= (void *)0x07000000 &&
-		    mh.mh_Lower <  (void *)0x08000000 &&
-		    (mh.mh_Attributes & MEMF_LOCAL))
-			bi.bi_amiga.model = AMI_3000;
-
-		/* mask the memory limit values */
-		mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
-		mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
-		/* if fast memory */
-		if (mh.mh_Attributes & MEMF_FAST) {
-			unsigned long size;
-
-			/* record the start */
-			bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
-
-			/* set the size value to the size of this block */
-			size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower;
-
-			/* mask off to a 256K increment */
-			size &= 0xfffc0000;
-
-			fast_total += size;
-
-			if (size > 0)
-				/* count this block */
-				bi.memory[bi.num_memory++].size  = size;
-
-		} else if (mh.mh_Attributes & MEMF_CHIP) {
-			/* if CHIP memory, record the size */
-			bi.bi_amiga.chip_size =
-				(u_long)mh.mh_Upper; /* - (u_long)mh.mh_Lower; */
-		}
-	}
+static int model = AMI_UNKNOWN;
 
-	CloseLibrary((struct Library *)ExpansionBase);
+static const char *ProgramName;
 
-	/*
-	 * if we have a memory file, read the memory information from it
-	 */
-	if (memfile) {
-	    FILE *fp;
-	    int i;
-
-	    if ((fp = fopen (memfile, "r")) == NULL) {
-		perror ("open memory file");
-		fprintf (stderr, "Cannot open memory file %s\n", memfile);
-		exit (EXIT_FAILURE);
-	    }
+struct linuxboot_args args;
 
-	    if (fscanf (fp, "%lu", &bi.bi_amiga.chip_size) != 1) {
-		fprintf (stderr, "memory file does not contain chip memory size\n");
-		fclose (fp);
-		exit (EXIT_FAILURE);
-	    }
-		
-	    for (i = 0; i < NUM_MEMINFO; i++) {
-		if (fscanf (fp, "%lx %lu", &bi.memory[i].addr,
-			    &bi.memory[i].size) != 2)
-		    break;
-	    }
 
-	    fclose (fp);
+    /*
+     *  Function Prototypes
+     */
 
-	    if (i != bi.num_memory && i > 0)
-		bi.num_memory = i;
-	}
+static void Usage(void) __attribute__ ((noreturn));
+int main(int argc, char *argv[]);
+static void Puts(const char *str);
+static long GetChar(void);
+static void PutChar(char c);
+static void Printf(const char *fmt, ...);
+static int Open(const char *path);
+static int Seek(int fd, int offset);
+static int Read(int fd, char *buf, int count);
+static void Close(int fd);
+static int FileSize(const char *path);
+static void Sleep(u_long micros);
+static int ModifyBootinfo(struct bootinfo *bi);
 
-	/* get info from ExecBase */
-	bi.bi_amiga.vblank = SysBase->VBlankFrequency;
-	bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
-	bi.bi_amiga.eclock = SysBase->EClockFrequency;
-
-	/* open graphics library */
-	GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
-
-	/* determine chipset */
-	bi.bi_amiga.chipset = CS_STONEAGE;
-	if(GfxBase)
-	{
-	    if(GfxBase->ChipRevBits0 & GFXG_AGA)
-	    {
-		bi.bi_amiga.chipset = CS_AGA;
-		/*
-		 *  we considered this machine to be an A3000 because of its
-		 *  local memory just beneath $8000000; now if it has AGA, it
-		 *  must be an A4000
-		 *  except the case no RAM is installed on the motherboard but
-		 *  on an additional card like FastLane Z3 or on the processor
-		 *  board itself. Gotta check this out.
-		 */
-		bi.bi_amiga.model =
-		    (bi.bi_amiga.model == AMI_3000) ? AMI_4000 : AMI_1200;
-	    }
-	    else if(GfxBase->ChipRevBits0 & GFXG_ECS)
-		bi.bi_amiga.chipset = CS_ECS;
-	    else if(GfxBase->ChipRevBits0 & GFXG_OCS)
-		bi.bi_amiga.chipset = CS_OCS;
-	}
 
-	/* Display amiga model */
-	switch (bi.bi_amiga.model) {
-	    case AMI_UNKNOWN:
-		break;
-	    case AMI_500:
-		printf ("Amiga 500 ");
-		break;
-	    case AMI_2000:
-		printf ("Amiga 2000 ");
-		break;
-	    case AMI_3000:
-		printf ("Amiga 3000 ");
-		break;
-	    case AMI_4000:
-		printf ("Amiga 4000 ");
-		break;
-	    case AMI_1200:		/* this implies an upgraded model   */
-		printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */
-		break;
-	}
-
-	/* display and set the CPU <type */
-	printf("CPU: ");
-	if (SysBase->AttnFlags & AFF_68040) {
-		printf("68040");
-		bi.cputype = CPU_68040;
-		if (SysBase->AttnFlags & AFF_FPU40) {
-			printf(" with internal FPU");
-			bi.cputype |= FPU_68040;
-		} else
-			printf(" without FPU");
-	} else {
-		if (SysBase->AttnFlags & AFF_68030) {
-			printf("68030");
-			bi.cputype = CPU_68030;
-		} else if (SysBase->AttnFlags & AFF_68020) {
-			printf("68020 (Do you have an MMU?)");
-			bi.cputype = CPU_68020;
-		} else {
-			puts("Insufficient for Linux.  Aborting...");
-			printf("SysBase->AttnFlags = %#x\n", SysBase->AttnFlags);
-			exit (EXIT_FAILURE);
-		}
-		if (SysBase->AttnFlags & AFF_68882) {
-			printf(" with 68882 FPU");
-			bi.cputype |= FPU_68882;
-		} else if (SysBase->AttnFlags & AFF_68881) {
-			printf(" with 68881 FPU");
-			bi.cputype |= FPU_68881;
-		} else
-			printf(" without FPU");
-	}
-
-	switch(bi.bi_amiga.chipset)
-	{
-	    case CS_STONEAGE:
-		printf(", old or unknown chipset");
-		break;
-	    case CS_OCS:
-		printf(", OCS");
-		break;
-	    case CS_ECS:
-		printf(", ECS");
-		break;
-	    case CS_AGA:
-		printf(", AGA chipset");
-		break;
-	}
-
-	putchar ('\n');
-	putchar ('\n');
-
-	/*
-	 * Copy command line options into the kernel command line.
-	 */
-	i = 0;
-	while (argc--) {
-		if ((i+strlen(*argv)+1) < CL_SIZE) {
-			i += strlen(*argv) + 1;
-			if (bi.command_line[0])
-				strcat (bi.command_line, " ");
-			strcat (bi.command_line, *argv++);
-		}
-	}
-	printf ("Command line is '%s'\n", bi.command_line);
-
-	/* display the clock statistics */
-	printf("Vertical Blank Frequency: %dHz\nPower Supply Frequency: %dHz\n",
-	       bi.bi_amiga.vblank, bi.bi_amiga.psfreq);
-	printf("EClock Frequency: %7.5fKHz\n\n",
-	       (float)bi.bi_amiga.eclock / 1000);
-
-	/* display autoconfig devices */
-	if (bi.bi_amiga.num_autocon) {
-		printf("Found %d AutoConfig Device%s", bi.bi_amiga.num_autocon,
-		       (bi.bi_amiga.num_autocon > 1)?"s\n":"\n");
-		for (i=0; i<bi.bi_amiga.num_autocon; i++)
-		{
-			printf("Device %d: addr = %08lx\n", i,
-			       (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
-			/* check for a Rainbow 3 and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH1) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_RAINBOW3) )
-			{
-				printf("(Found a Rainbow 3 board - will reset it at kernel boot time)\n");
-				rb3_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x01002000);
-			}
-
-			/* check for a Piccolo and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_PICCOLO_REG) )
-			{
-				printf("(Found a Piccolo board - will reset it at kernel boot time)\n");
-				piccolo_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
-			}
-
-			/* check for a SD64 and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_SD64_REG) )
-			{
-				printf("(Found a SD64 board - will reset it at kernel boot time)\n");
-				sd64_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
-			}
-
-			/* what this code lacks - what if there are several boards of  */
-			/* the same brand ? In that case I should reset them one after */
-			/* the other, which is currently not done - a rare case...FN   */
-			/* ok, MY amiga currently hosts all three of the above boards ;-) */
-		}
-	} else
-		puts("No AutoConfig Devices Found");
-
-	/* display memory */
-	if (bi.num_memory) {
-		printf("\n%d Block%sof Memory Found\n", bi.num_memory,
-		       (bi.num_memory > 1)?"s ":" ");
-		for (i=0; i<bi.num_memory; i++) {
-			printf("Block %d: %08lx to %08lx (%ldKB)\n",
-			       i, bi.memory[i].addr,
-			       bi.memory[i].addr + bi.memory[i].size,
-			       bi.memory[i].size >> 10);
-		}
-	} else {
-		puts("No memory found?!  Aborting...");
-		exit(10);
-	}
+static void Usage(void)
+{
+    fprintf(stderr,
+	    "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
+	    "Usage: %s [options] [kernel command line]\n\n"
+	    "Valid options are:\n"
+	    "    -h, --help           Display this usage information\n"
+	    "    -k, --kernel file    Use kernel image `file' (default is `vmlinux')\n"
+	    "    -r, --ramdisk file   Use ramdisk image `file'\n"
+	    "    -d, --debug          Enable debug mode\n"
+	    "    -m, --memfile file   Use memory file `file'\n"
+	    "    -v, --keep-video     Don't reset the video mode\n"
+	    "    -t, --model id       Set the Amiga model to `id'\n\n",
+	    ProgramName);
+    exit(EXIT_FAILURE);
+}
 
-	/* display chip memory size */
-	printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10);
 
-	start_mem = bi.memory[0].addr;
-	mem_size = bi.memory[0].size;
+int main(int argc, char *argv[])
+{
+    int i;
+    int debugflag = 0, keep_video = 0;
+    const char *kernel_name = NULL;
+    const char *ramdisk_name = NULL;
+    char commandline[CL_SIZE] = "";
+
+    ProgramName = argv[0];
+    while (--argc) {
+	argv++;
+	if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
+	    Usage();
+	else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
+            if (--argc && !kernel_name) {
+                kernel_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
+            if (--argc && !ramdisk_name) {
+                ramdisk_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
+	    debugflag = 1;
+	else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
+            if (--argc && !memfile_name) {
+                memfile_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
+	    keep_video = 1;
+	else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
+            if (--argc && !model) {
+                model = atoi(argv[1]);
+                argv++;
+            } else
+                Usage();
+	else
+	    break;
+    }
+    if (!kernel_name)
+	kernel_name = "vmlinux";
+
+    SysBase = *(struct ExecBase **)4;
+
+    /* open Expansion Library */
+    ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
+							36);
+    if (!ExpansionBase) {
+	fputs("Unable to open expansion.library V36 or greater!  Aborting...\n",
+	      stderr);
+	exit(EXIT_FAILURE);
+   }
+
+    /* open Graphics Library */
+    GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
+    if (!GfxBase) {
+	fputs("Unable to open graphics.library!  Aborting...\n", stderr);
+	exit(EXIT_FAILURE);
+    }
+
+    /*
+     *	Join command line options
+     */
+    i = 0;
+    while (argc--) {
+	if ((i+strlen(*argv)+1) < CL_SIZE) {
+	    i += strlen(*argv) + 1;
+	    if (commandline[0])
+		strcat(commandline, " ");
+	    strcat(commandline, *argv++);
+	}
+    }
+
+    args.kernelname = kernel_name;
+    args.ramdiskname = ramdisk_name;
+    args.commandline = commandline;
+    args.debugflag = debugflag;
+    args.keep_video = keep_video;
+    args.reset_boards = 1;
+    args.puts = Puts;
+    args.getchar = GetChar;
+    args.putchar = PutChar;
+    args.printf = Printf;
+    args.open = Open;
+    args.seek = Seek;
+    args.read = Read;
+    args.close = Close;
+    args.filesize = FileSize;
+    args.sleep = Sleep;
+    args.modify_bootinfo = ModifyBootinfo;
 
-	/* tell us where the kernel will go */
-	printf("\nThe kernel will be located at %08lx\n", start_mem);
+    /* Do The Right Stuff */
+    linuxboot(&args);
 
-	/* verify that there is enough Chip RAM */
-	if (bi.bi_amiga.chip_size < 512*1024) {
-		puts("\nNot enough Chip RAM in this system.  Aborting...");
-		exit(10);
-	}
+    CloseLibrary((struct Library *)GfxBase);
+    CloseLibrary((struct Library *)ExpansionBase);
 
-	/* verify that there is enough Fast RAM */
-	if (fast_total < 2*1024*1024) {
-		puts("\nNot enough Fast RAM in this system.  Aborting...");
-		exit(10);
-	}
+    /* if we ever get here, something went wrong */
+    exit(EXIT_FAILURE);
+}
 
-	/* open kernel executable and read exec header */
-	if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
-		fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
-		exit (EXIT_FAILURE);
-	}
 
-	if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
-		fprintf (stderr, "Unable to read exec header from %s\n",
-			 kernel_name);
-		exit (EXIT_FAILURE);
-	}
+    /*
+     *  Routines needed by linuxboot
+     */
 
-	switch (N_MAGIC(kexec)) {
-	  case ZMAGIC:
-	    text_offset = N_TXTOFF(kexec);
-	    break;
-	  case QMAGIC:
-	    text_offset = sizeof(kexec);
-	    /* the text size includes the exec header; remove this */
-	    kexec.a_text -= sizeof(kexec);
-	    break;
-	  default:
-	    fprintf (stderr, "Wrong magic number %lo in kernel header\n",
-		     N_MAGIC(kexec));
-	    exit (EXIT_FAILURE);
-	}
+static void Puts(const char *str)
+{
+    fputs(str, stderr);
+}
 
-	/* Load the kernel at one page after start of mem */
-	start_mem += PAGE_SIZE;
-	mem_size -= PAGE_SIZE;
-	/* Align bss size to multiple of four */
-	kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
-	if (ramdisk_name) {
-		if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) {
-			fprintf (stderr, "Unable to open ramdisk file %s\n",
-				 ramdisk_name);
-			exit (EXIT_FAILURE);
-		}
-		/* record ramdisk size */
-		bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10;
-	} else
-		bi.ramdisk_size = 0;
-
-	rd_size = bi.ramdisk_size << 10;
-	bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
-
-	memreq = kexec.a_text + kexec.a_data + sizeof(bi) + rd_size;
-	if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
-		fprintf (stderr, "Unable to allocate memory\n");
-		exit (EXIT_FAILURE);
-	}
+static long GetChar(void)
+{
+    return(getchar());
+}
 
-	if (lseek (kfd, text_offset, L_SET) == -1) {
-		fprintf (stderr, "Failed to seek to text\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
-	if (read (kfd, memptr, kexec.a_text) != kexec.a_text) {
-		fprintf (stderr, "Failed to read text\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
+static void PutChar(char c)
+{
+    fputc(c, stderr);
+}
 
-	/* data follows immediately after text */
-	if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) {
-		fprintf (stderr, "Failed to read data\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
-	close (kfd);
+static void Printf(const char *fmt, ...)
+{
+    va_list args;
 
-	/* copy the boot_info struct to the end of the kernel image */
-	memcpy ((void *)(memptr + kexec.a_text + kexec.a_data), &bi,
-		sizeof(bi));
-
-	if (rfd != -1) {
-		if (lseek (rfd, 0, L_SET) == -1) {
-			fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
-			FreeMem ((void *)memptr, memreq);
-			exit (EXIT_FAILURE);
-		}
-		if (read (rfd, memptr + kexec.a_text + kexec.a_data 
-			  + sizeof(bi), rd_size) != rd_size) {
-			fprintf (stderr, "Failed to read ramdisk file\n");
-			FreeMem ((void *)memptr, memreq);
-			exit (EXIT_FAILURE);
-		}
-		close (rfd);
-	}
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
 
-	/* allocate temporary chip ram stack */
-	stack = (u_long *)AllocMem( TEMP_STACKSIZE, MEMF_CHIP|MEMF_CLEAR);
-	if (!stack) {
-		fprintf (stderr, "Unable to allocate memory for stack\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
+static int Open(const char *path)
+{
+    return(open(path, O_RDONLY));
+}
 
-	/* allocate chip ram for copy of startup code */
-	startcodesize = &copyallend - &copyall;
-	startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP);
-	if (!startfunc) {
-		fprintf (stderr, "Unable to allocate memory for code\n");
-		FreeMem ((void *)memptr, memreq);
-		FreeMem ((void *)stack, TEMP_STACKSIZE);
-		exit (EXIT_FAILURE);
-	}
+static int Seek(int fd, int offset)
+{
+    return(lseek(fd, offset, SEEK_SET));
+}
 
-	/* copy startup code to CHIP RAM */
-	memcpy (startfunc, &copyall, startcodesize);
 
-	if (debugflag) {
-		if (bi.ramdisk_size)
-			printf ("RAM disk at %#lx, size is %ldK\n",
-				(u_long)memptr + kexec.a_text + kexec.a_data,
-				bi.ramdisk_size);
-
-		printf ("\nKernel text at %#lx, code size %x\n",
-			start_mem, kexec.a_text);
-		printf ("Kernel data at %#lx, data size %x\n",
-			start_mem + kexec.a_text, kexec.a_data );
-		printf ("Kernel bss  at %#lx, bss  size %x\n",
-			start_mem + kexec.a_text + kexec.a_data,
-			kexec.a_bss );
-		printf ("boot info at %#lx\n", start_mem + kexec.a_text
-			+ kexec.a_data + kexec.a_bss);
-
-		printf ("\nKernel entry is %#x\n", kexec.a_entry );
-
-		printf ("ramdisk dest top is %#lx\n", start_mem + mem_size);
-		printf ("ramdisk lower limit is %#lx\n",
-			(u_long)(memptr + kexec.a_text + kexec.a_data));
-		printf ("ramdisk src top is %#lx\n",
-			(u_long)(memptr + kexec.a_text + kexec.a_data)
-			+ rd_size);
-
-		printf ("Type a key to continue the Linux boot...");
-		fflush (stdout);
-		getchar();
-	}
+static int Read(int fd, char *buf, int count)
+{
+    return(read(fd, buf, count));
+}
 
-	/* wait for things to settle down */
-	sleep(2);
+static void Close(int fd)
+{
+    close(fd);
+}
 
-	/* FN: If a Rainbow III board is present, reset it to disable */
-	/* its (possibly activated) vertical blank interrupts as the */
-	/* kernel is not yet prepared to handle them (level 6). */
-	if (rb3_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*rb3_reg = 0x01;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-		/* clear reset bit */
-		*rb3_reg = 0x00;
-	}
+static int FileSize(const char *path)
+{
+    int fd, size = -1;
 
-	/* the same stuff as above, for the Piccolo board. */
-	/* this also has the side effect of resetting the board's */
-	/* output selection logic to use the Amiga's display in single */
-	/* monitor systems - which is currently what we want. */
-	if (piccolo_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*piccolo_reg = 0x01;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-		/* clear reset bit */
-		*piccolo_reg = 0x51;
-	}
+    if ((fd = open(path, O_RDONLY)) != -1) {
+        size = lseek(fd, 0, SEEK_END);
+        close(fd);
+    }
+    return(size);
+}
 
-	/* the same stuff as above, for the SD64 board. */
-	/* just as on the Piccolo, this also resets the monitor switch */
-	if (sd64_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*sd64_reg = 0x1f;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-	/* clear reset bit AND switch monitor bit (0x20) */
-	*sd64_reg = 0x4f;
-	}
+static void Sleep(u_long micros)
+{
+    struct MsgPort *TimerPort;
+    struct timerequest *TimerRequest;
 
-	if (GfxBase) {
-		/* set graphics mode to a nice normal one */
-		LoadView (NULL);
-		CloseLibrary ((struct Library *)GfxBase);
+    if ((TimerPort = CreateMsgPort())) {
+	if ((TimerRequest = CreateIORequest(TimerPort,
+					    sizeof(struct timerequest)))) {
+	    if (!OpenDevice("timer.device", UNIT_VBLANK,
+			    (struct IORequest *)TimerRequest, 0)) {
+		TimerRequest->io_Command = TR_ADDREQUEST;
+		TimerRequest->io_Flags = IOF_QUICK;
+		TimerRequest->tv_secs = micros/1000000;
+		TimerRequest->tv_micro = micros%1000000;
+		DoIO((struct IORequest *)TimerRequest);
+		CloseDevice((struct IORequest *)TimerRequest);
+	    }
+	    DeleteIORequest(TimerRequest);
 	}
+	DeleteMsgPort(TimerPort);
+    }
+}
 
-	Disable();
-
-	/* Turn off all DMA */
-	custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-	/* turn off caches */
-	CacheControl (0L, ~0L);
-
-	/* Go into supervisor state */
-	SuperState ();
-
-	/* setup stack */
-	change_stack ((char *) stack + TEMP_STACKSIZE);
-
-	/* turn off any mmu translation */
-	disable_mmu ();
 
-	/* execute the copy-and-go code (from CHIP RAM) */
-	startfunc();
+static int ModifyBootinfo(struct bootinfo *bi)
+{
+   /*
+    * if we have a memory file, read the memory information from it
+    */
+   if (memfile_name) {
+      FILE *fp;
+      int i;
+
+      if ((fp = fopen(memfile_name, "r")) == NULL) {
+         perror("open memory file");
+         fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
+         return(FALSE);
+      }
+
+      if (fscanf(fp, "%lu", &bi->bi_amiga.chip_size) != 1) {
+         fprintf(stderr, "memory file does not contain chip memory size\n");
+         fclose(fp);
+         return(FALSE);
+      }
+                
+      for (i = 0; i < NUM_MEMINFO; i++) {
+         if (fscanf(fp, "%lx %lu", &bi->memory[i].addr, &bi->memory[i].size)
+	     != 2)
+            break;
+      }
+
+      fclose(fp);
+
+      if (i != bi->num_memory && i > 0)
+         bi->num_memory = i;
+   }
+
+   /*
+    * change the Amiga model, if necessary
+    */
+   if (model != AMI_UNKNOWN)
+      bi->bi_amiga.model = model;
 
-	/* NOTREACHED */
+   return(TRUE);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/bootstrap.h linux/arch/m68k/boot/amiga/bootstrap.h
--- lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/bootstrap.h	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/boot/amiga/bootstrap.h	Wed Sep 25 10:47:38 1996
@@ -1,12 +1,18 @@
 /*
-** bootstrap.h -- This file is a part of the Amiga bootloader.
+** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
+**					     bootloader.
 **
 ** Copyright 1993, 1994 by Hamish Macdonald
 **
 ** Some minor additions by Michael Rausch 1-11-94
 ** Modified 11-May-94 by Geert Uytterhoeven
-**                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
 **     - inline Supervisor() call
+** Modified 10-Jan-96 by Geert Uytterhoeven
+**     - The real Linux/m68k boot code moved to linuxboot.[ch]
+** Modified 9-Sep-96 by Geert Uytterhoeven
+**     - const library bases
+**     - fixed register naming for m68k-cbm-amigados-gcc
 **
 ** 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
@@ -14,316 +20,156 @@
 **
 */
 
-#ifndef BOOTSTRAP_H
-#define BOOTSTRAP_H
-
 #include <asm/amigatypes.h>
-#include <asm/amigahw.h>
 
-struct List {
-    struct Node *l_head;
-    struct Node *l_tail;
-    struct Node *l_tailpred;
-    u_char  l_type;
-    u_char  l_pad;
-};
 
-struct MemChunk {
-    struct  MemChunk *mc_Next;	/* pointer to next chunk */
-    u_long   mc_Bytes;		/* chunk byte size	*/
+struct MsgPort {
+    u_char fill1[15];
+    u_char mp_SigBit;
+    u_char fill2[18];
 };
 
-#define MEMF_CHIP  (1<<1)
-#define MEMF_FAST  (1<<2)
-#define MEMF_LOCAL (1<<8)
-#define MEMF_CLEAR (1<<16)
-
-struct MemHeader {
-    struct  Node mh_Node;
-    u_short   mh_Attributes;	/* characteristics of this region */
-    struct  MemChunk *mh_First; /* first free region		*/
-    void    *mh_Lower;		/* lower memory bound		*/
-    void    *mh_Upper;		/* upper memory bound+1 */
-    u_long   mh_Free;		/* total number of free bytes	*/
+struct IOStdReq {
+    u_char fill1[20];
+    struct Device *io_Device;
+    u_char fill2[4];
+    u_short io_Command;
+    u_char io_Flags;
+    char io_Error;
+    u_long io_Actual;
+    u_long io_Length;
+    void *io_Data;
+    u_char fill4[4];
 };
 
-struct ExecBase {
-    u_char	fill1[296];
-    u_short	AttnFlags;
-    u_char	fill2[24];
-    struct List MemList;
-    u_char	fill3[194];
-    u_char	VBlankFrequency;
-    u_char	PowerSupplyFrequency;
-    u_char	fill4[36];
-    u_long	EClockFrequency;
-};
+#define IOF_QUICK	(1<<0)
 
-#ifndef AFF_68020
-#define AFB_68020 1
-#define AFF_68020 (1<<AFB_68020)
-#endif
-
-#ifndef AFF_68030
-#define AFB_68030 2
-#define AFF_68030 (1<<AFB_68030)
-#endif
-
-#ifndef AFF_68040
-#define AFB_68040 3
-#define AFF_68040 (1<<AFB_68040)
-#endif
-
-#ifndef AFF_68881
-#define AFB_68881 4
-#define AFF_68881 (1<<AFB_68881)
-#endif
-
-#ifndef AFF_68882
-#define AFB_68882 5
-#define AFF_68882 (1<<AFB_68882)
-#endif
-
-#ifndef AFF_FPU40
-#define AFB_FPU40 6
-#define AFF_FPU40 (1<<AFB_FPU40)
-#endif
-
-/*
- *  GfxBase is now used to determine if AGA or ECS is present
- */
-
-struct GfxBase {
-	u_char	unused1[0xec];
-	u_char	ChipRevBits0;
-	u_char	unused2[5];
-	u_short	monitor_id;
+struct timerequest {
+    u_char fill1[28];
+    u_short io_Command;
+    u_char io_Flags;
+    u_char fill2[1];
+    u_long tv_secs;
+    u_long tv_micro;
 };
 
-#ifndef	GFXB_HR_AGNUS
-#define	GFXB_HR_AGNUS	0
-#define	GFXF_HR_AGNUS	(1<<GFXB_HR_AGNUS)
-#endif
-
-#ifndef	GFXB_HR_DENISE
-#define GFXB_HR_DENISE	1
-#define GFXF_HR_DENISE	(1<<GFXB_HR_DENISE)
-#endif
-
-#ifndef	GFXB_AA_ALICE
-#define GFXB_AA_ALICE	2
-#define GFXF_AA_ALICE	(1<<GFXB_AA_ALICE)
-#endif
-
-#ifndef	GFXB_AA_LISA
-#define GFXB_AA_LISA	3
-#define GFXF_AA_LISA	(1<<GFXB_AA_LISA)
-#endif
-
-/*
- *  HiRes(=Big) Agnus present; i.e. 
- *  1MB chipmem, big blits (none of interest so far) and programmable sync
- */
-#define GFXG_OCS	(GFXF_HR_AGNUS)
-/*
- *  HiRes Agnus/Denise present; we are running on ECS
- */
-#define GFXG_ECS	(GFXF_HR_AGNUS|GFXF_HR_DENISE)
-/*
- *  Alice and Lisa present; we are running on AGA
- */
-#define GFXG_AGA	(GFXF_AA_ALICE|GFXF_AA_LISA)
+#define UNIT_VBLANK	1
+#define TR_ADDREQUEST	9
+
 
 struct Library;
+struct IORequest;
 
-extern struct ExecBase *SysBase;
 
-static __inline void *
-AllocMem (unsigned long byteSize,unsigned long requirements)
-{
-  register void  *_res	__asm("d0");
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register unsigned long d0 __asm("d0") = byteSize;
-  register unsigned long d1 __asm("d1") = requirements;
-  __asm __volatile ("jsr a6@(-0xc6)"
-  : "=r" (_res)
-  : "r" (a6), "r" (d0), "r" (d1)
-  : "a0","a1","d0","d1", "memory");
-  return _res;
-}
-static __inline void
-CloseLibrary (struct Library *library)
-{
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register struct Library *a1 __asm("a1") = library;
-  __asm __volatile ("jsr a6@(-0x19e)"
-  : /* no output */
-  : "r" (a6), "r" (a1)
-  : "a0","a1","d0","d1", "memory");
-}
-static __inline void
-Disable (void)
-{
-  extern struct ExecBase *SysBase;
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  __asm __volatile ("jsr a6@(-0x78)"
-  : /* no output */
-  : "r" (a6)
-  : "a0","a1","d0","d1", "memory");
-}
-static __inline void
-Enable (void)
-{
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  __asm __volatile ("jsr a6@(-0x7e)"
-  : /* no output */
-  : "r" (a6)
-  : "a0","a1","d0","d1", "memory");
-}
-static __inline void
-FreeMem (void * memoryBlock,unsigned long byteSize)
-{
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register void *a1 __asm("a1") = memoryBlock;
-  register unsigned long d0 __asm("d0") = byteSize;
-  __asm __volatile ("jsr a6@(-0xd2)"
-  : /* no output */
-  : "r" (a6), "r" (a1), "r" (d0)
-  : "a0","a1","d0","d1", "memory");
-}
-static __inline struct Library *
-OpenLibrary (char *libName,unsigned long version)
-{
-  register struct Library * _res  __asm("d0");
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register u_char *a1 __asm("a1") = libName;
-  register unsigned long d0 __asm("d0") = version;
-  __asm __volatile ("jsr a6@(-0x228)"
-  : "=r" (_res)
-  : "r" (a6), "r" (a1), "r" (d0)
-  : "a0","a1","d0","d1", "memory");
-  return _res;
-}
-static __inline void *
-SuperState (void)
-{
-  register void  *_res	__asm("d0");
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  __asm __volatile ("jsr a6@(-0x96)"
-  : "=r" (_res)
-  : "r" (a6)
-  : "a0","a1","d0","d1", "memory");
-  return _res;
-}
-static __inline void 
-CacheClearU (void)
-{
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  __asm __volatile ("jsr a6@(-0x27c)"
-  : /* no output */
-  : "r" (a6)
-  : "a0","a1","d0","d1", "memory");
-}
-static __inline unsigned long 
-CacheControl (unsigned long cacheBits,unsigned long cacheMask)
+static __inline void CloseLibrary(struct Library *library)
 {
-  register unsigned long  _res  __asm("d0");
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register unsigned long d0 __asm("d0") = cacheBits;
-  register unsigned long d1 __asm("d1") = cacheMask;
-  __asm __volatile ("jsr a6@(-0x288)"
-  : "=r" (_res)
-  : "r" (a6), "r" (d0), "r" (d1)
-  : "a0","a1","d0","d1", "memory");
-  return _res;
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register struct Library *a1 __asm("a1") = library;
+    __asm __volatile ("jsr a6@(-0x19e)"
+		      : /* no output */
+		      : "r" (a6), "r" (a1)
+		      : "a0","a1","d0","d1", "memory");
 }
-static __inline unsigned long
-Supervisor (unsigned long (*userfunc)())
+
+static __inline struct Library *OpenLibrary(char *libName,
+					    unsigned long version)
 {
-  register unsigned long _res __asm("d0");
-  register struct ExecBase *a6 __asm("a6") = SysBase;
-  register unsigned long (*a0)() __asm("a0") = userfunc;
-	/* gcc doesn't seem to like asm parameters in a5 */
-  __asm __volatile ("movel a5,sp@-;movel a0,a5;jsr a6@(-0x1e);movel sp@+,a5"
-  : "=r" (_res)
-  : "r" (a6), "r" (a0)
-  : "a0","a1","d0","d1","memory");
-  return _res;
+    register struct Library * _res  __asm("d0");
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register u_char *a1 __asm("a1") = libName;
+    register unsigned long d0 __asm("d0") = version;
+    __asm __volatile ("jsr a6@(-0x228)"
+		      : "=r" (_res)
+		      : "r" (a6), "r" (a1), "r" (d0)
+		      : "a0","a1","d0","d1", "memory");
+    return _res;
 }
 
+static __inline char OpenDevice(u_char *devName, u_long unit,
+				struct IORequest *ioRequest, u_long flags)
+{
+    register char _res __asm("d0");
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register u_char *a0 __asm("a0") = devName;
+    register u_long d0 __asm("d0") = unit;
+    register struct IORequest *a1 __asm("a1") = ioRequest;
+    register u_long d1 __asm("d1") = flags;
 
-struct ExpansionBase;
-extern struct ExpansionBase *ExpansionBase;
+    __asm __volatile ("jsr a6@(-0x1bc)"
+		      : "=r" (_res)
+		      : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
+		      : "a0","a1","d0","d1", "memory");
+    return(_res);
+}
 
-static __inline struct ConfigDev *
-FindConfigDev (struct ConfigDev *oldConfigDev,long manufacturer,long product)
+static __inline void CloseDevice(struct IORequest *ioRequest)
 {
-  register struct ConfigDev * _res  __asm("d0");
-  register struct ExpansionBase* a6 __asm("a6") = ExpansionBase;
-  register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
-  register long d0 __asm("d0") = manufacturer;
-  register long d1 __asm("d1") = product;
-  __asm __volatile ("jsr a6@(-0x48)"
-  : "=r" (_res)
-  : "r" (a6), "r" (a0), "r" (d0), "r" (d1)
-  : "a0","a1","d0","d1", "memory");
-  return _res;
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register struct IORequest *a1 __asm("a1") = ioRequest;
+
+    __asm __volatile ("jsr a6@(-0x1c2)"
+		      : /* no output */
+		      : "r" (a6), "r" (a1)
+		      : "a0","a1","d0","d1", "memory");
 }
 
-struct GfxBase;
-extern struct GfxBase *GfxBase;
-struct View;
-static __inline void 
-LoadView (struct View *view)
+static __inline char DoIO(struct IORequest *ioRequest)
 {
-  register struct GfxBase* a6 __asm("a6") = GfxBase;
-  register struct View *a1 __asm("a1") = view;
-  __asm __volatile ("jsr a6@(-0xde)"
-  : /* no output */
-  : "r" (a6), "r" (a1)
-  : "a0","a1","d0","d1", "memory");
+    register char _res __asm("d0");
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register struct IORequest *a1 __asm("a1") = ioRequest;
+
+    __asm __volatile ("jsr a6@(-0x1c8)"
+		      : "=r" (_res)
+		      : "r" (a6), "r" (a1)
+		      : "a0","a1","d0","d1", "memory");
+    return(_res);
 }
 
-static __inline void change_stack (char *stackp)
+static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
 {
-    __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
+    register struct Library *_res __asm("d0");
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register struct MsgPort *a0 __asm("a0") = port;
+    register u_long d0 __asm("d0") = size;
+
+    __asm __volatile ("jsr a6@(-0x28e)"
+		      : "=r" (_res)
+		      : "r" (a6), "r" (a0), "r" (d0)
+		      : "a0","a1","d0","d1", "memory");
+    return(_res);
 }
 
-static __inline void disable_cache (void)
+static __inline void DeleteIORequest(void *ioRequest)
 {
-    __asm__ volatile ("movec %0,cacr" :: "d" (0));
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register void *a0 __asm("a0") = ioRequest;
+
+    __asm __volatile ("jsr a6@(-0x294)"
+		      : /* no output */
+		      : "r" (a6), "r" (a0)
+		      : "a0","a1","d0","d1", "memory");
 }
 
-static __inline void disable_mmu (void)
+static __inline struct MsgPort *CreateMsgPort(void)
 {
-    if (SysBase->AttnFlags & AFF_68040)
-	    __asm__ volatile ("moveq #0,d0;"
-			      ".long 0x4e7b0003;"	/* movec d0,tc */
-			      ".long 0x4e7b0004;"	/* movec d0,itt0 */
-			      ".long 0x4e7b0005;"	/* movec d0,itt1 */
-			      ".long 0x4e7b0006;"	/* movec d0,dtt0 */
-			      ".long 0x4e7b0007"	/* movec d0,dtt1 */
-			      : /* no outputs */
-			      : /* no inputs */
-			      : "d0");
-    else {
-	    __asm__ volatile ("subl  #4,sp;"
-			      "pmove tc,sp@;"
-			      "bclr  #7,sp@;"
-			      "pmove sp@,tc;"
-			      "addl  #4,sp");
-	    if (SysBase->AttnFlags & AFF_68030)
-		    __asm__ volatile ("clrl  sp@-;"
-				      ".long 0xf0170800;" /* pmove sp@,tt0 */
-				      ".long 0xf0170c00;" /* pmove sp@,tt1 */
-				      "addql #4,sp");
-    }
+    register struct MsgPort *_res __asm("d0");
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+
+    __asm __volatile ("jsr a6@(-0x29a)"
+		      : "=r" (_res)
+		      : "r" (a6)
+		      : "a0","a1","d0","d1", "memory");
+    return(_res);
 }
 
-static __inline void jump_to (unsigned long addr)
+static __inline void DeleteMsgPort(struct MsgPort *port)
 {
-    __asm__ volatile ("jmp %0@" :: "a" (addr));
-    /* NOTREACHED */
-}
+    register const struct ExecBase *a6 __asm("a6") = SysBase;
+    register struct MsgPort *a0 __asm("a0") = port;
 
-#endif /* BOOTSTRAP_H */
+    __asm __volatile ("jsr a6@(-0x2a0)"
+		      : /* no output */
+		      : "r" (a6), "r" (a0)
+		      : "a0","a1","d0","d1", "memory");
+}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/linuxboot.c linux/arch/m68k/boot/amiga/linuxboot.c
--- lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/linuxboot.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/amiga/linuxboot.c	Wed Sep 25 10:47:38 1996
@@ -0,0 +1,1128 @@
+/*
+ *  linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
+ *					      on Amiga, used by both Amiboot and
+ *					      Amiga-Lilo.
+ *
+ *	Created 1996 by Geert Uytterhoeven
+ *
+ *
+ *  This file is based on the original bootstrap code (bootstrap.c):
+ *
+ *	Copyright (C) 1993, 1994 Hamish Macdonald
+ *				 Greg Harp
+ *
+ *		    with work by Michael Rausch
+ *				 Geert Uytterhoeven
+ *				 Frank Neumann
+ *				 Andreas Schwab
+ *
+ *
+ *  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 __GNUC__
+#error GNU CC is required to compile this program
+#endif /* __GNUC__ */
+
+
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/linkage.h>
+#include <asm/setup.h>
+#include <asm/amigatypes.h>
+#include <asm/amigahw.h>
+#include <asm/page.h>
+
+#include "linuxboot.h"
+
+
+#undef custom
+#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
+
+/* temporary stack size */
+#define TEMP_STACKSIZE  (256)
+
+extern char copyall, copyallend;
+
+static struct exec kexec;
+static Elf32_Ehdr kexec_elf;
+static struct bootinfo bi;
+
+static const struct linuxboot_args *linuxboot_args;
+
+#define kernelname	linuxboot_args->kernelname
+#define ramdiskname	linuxboot_args->ramdiskname
+#define commandline	linuxboot_args->commandline
+#define debugflag	linuxboot_args->debugflag
+#define keep_video	linuxboot_args->keep_video
+#define reset_boards	linuxboot_args->reset_boards
+
+#define Puts		linuxboot_args->puts
+#define GetChar		linuxboot_args->getchar
+#define PutChar		linuxboot_args->putchar
+#define Printf		linuxboot_args->printf
+#define Open		linuxboot_args->open
+#define Seek		linuxboot_args->seek
+#define Read		linuxboot_args->read
+#define Close		linuxboot_args->close
+#define FileSize	linuxboot_args->filesize
+#define Sleep		linuxboot_args->sleep
+#define ModifyBootinfo	linuxboot_args->modify_bootinfo
+
+
+    /*
+     *  Function Prototypes
+     */
+
+static u_long get_chipset(void);
+static u_long get_cpu(void);
+static u_long get_model(u_long chipset);
+static int probe_resident(const char *name);
+static int probe_resource(const char *name);
+static int check_bootinfo_version(const char *memptr);
+static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
+			 u_long start_mem, u_long mem_size, u_long rd_size,
+			 u_long kernel_size) __attribute__ ((noreturn));
+asmlinkage u_long maprommed(void);
+
+
+    /*
+     *	Reset functions for nasty Zorro boards
+     */
+
+static void reset_rb3(const struct ConfigDev *cd);
+static void reset_piccolo(const struct ConfigDev *cd);
+static void reset_sd64(const struct ConfigDev *cd);
+static void reset_ariadne(const struct ConfigDev *cd);
+static void reset_hydra(const struct ConfigDev *cd);
+#if 0
+static void reset_a2060(const struct ConfigDev *cd);
+#endif
+
+struct boardreset {
+    u_short manuf;
+    u_short prod;
+    const char *name;
+    void (*reset)(const struct ConfigDev *cd);
+};
+
+static struct boardreset boardresetdb[] = {
+    { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
+    { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
+    { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
+    { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
+    { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
+#if 0
+    { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
+#endif
+};
+#define NUM_BOARDRESET	sizeof(boardresetdb)/sizeof(*boardresetdb)
+
+static void (*boardresetfuncs[NUM_AUTO])(const struct ConfigDev *cd);
+
+
+const char *amiga_models[] = {
+    "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
+    "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
+    "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
+};
+const u_long first_amiga_model = AMI_500;
+const u_long last_amiga_model = AMI_DRACO;
+
+
+#define MASK(model)	(1<<AMI_##model)
+
+#define CLASS_A3000	(MASK(3000) | MASK(3000T))
+#define CLASS_A4000	(MASK(4000) | MASK(4000T))
+#define CLASS_ZKICK	(MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
+
+
+    /*
+     *	Boot the Linux/m68k Operating System
+     */
+
+u_long linuxboot(const struct linuxboot_args *args)
+{
+    int kfd = -1, rfd = -1, elf_kernel = 0;
+    int i, j;
+    const struct MemHeader *mnp;
+    struct ConfigDev *cdp = NULL;
+    char *memptr = NULL;
+    u_long *stack = NULL;
+    u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
+    u_long kernel_size;
+    u_long memreq = 0, text_offset = 0;
+    Elf32_Phdr *kernel_phdrs = NULL;
+    void (*startfunc)(void);
+    u_short manuf;
+    u_char prod;
+
+    linuxboot_args = args;
+
+    /* print the greet message */
+    Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
+    Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
+
+    /* machine is Amiga */
+    bi.machtype = MACH_AMIGA;
+
+    /* determine chipset */
+    bi.bi_amiga.chipset = get_chipset();
+
+    /* determine CPU type */
+    bi.cputype = get_cpu();
+
+    /* determine Amiga model */
+    bi.bi_amiga.model = get_model(bi.bi_amiga.chipset);
+    model_mask = (bi.bi_amiga.model != AMI_UNKNOWN) ? 1<<bi.bi_amiga.model : 0;
+
+    /* Memory & AutoConfig based on 'unix_boot.c' by C= */
+
+    /* find all of the autoconfig boards in the system */
+    bi.bi_amiga.num_autocon = 0;
+    for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++) {
+	if (bi.bi_amiga.num_autocon < NUM_AUTO) {
+	    /* copy the contents of each structure into our boot info */
+	    memcpy(&bi.bi_amiga.autocon[bi.bi_amiga.num_autocon], cdp,
+		   sizeof(struct ConfigDev));
+	    /* count this device */
+	    bi.bi_amiga.num_autocon++;
+	} else
+	    Printf("Warning: too many AutoConfig devices. Ignoring device at "
+		   "0x%08lx\n", cdp->cd_BoardAddr);
+    }
+
+    /* find out the memory in the system */
+    bi.num_memory = 0;
+    for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
+	 mnp->mh_Node.ln_Succ;
+	 mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
+	struct MemHeader mh;
+
+	/* copy the information */
+	mh = *mnp;
+
+	/* skip virtual memory */
+	if (!(mh.mh_Attributes & MEMF_PUBLIC))
+	    continue;
+
+	/* if we suspect that Kickstart is shadowed in an A3000,
+	   modify the entry to show 512K more at the top of RAM
+	   Check first for a MapROMmed A3640 board: overwriting the
+	   Kickstart image causes an infinite lock-up on reboot! */
+	if ((mh.mh_Upper == (void *)0x07f80000) &&
+	    (model_mask & (CLASS_A3000 | CLASS_A4000)))
+	    if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
+		Puts("A3640 MapROM detected.\n");
+	    else if (model_mask & CLASS_A3000) {
+		mh.mh_Upper = (void *)0x08000000;
+		Puts("A3000 shadowed Kickstart detected.\n");
+	    }
+
+	/* if we suspect that Kickstart is zkicked,
+	   modify the entry to show 512K more at the botton of RAM */
+	if ((mh.mh_Lower == (void *)0x00280020) &&
+	    (model_mask & CLASS_ZKICK)) {
+	    mh.mh_Lower = (void *)0x00200000;
+	    Puts("ZKick detected.\n");
+	}
+
+	/* mask the memory limit values */
+	mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
+	mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
+
+	/* if fast memory */
+	if (mh.mh_Attributes & MEMF_FAST) {
+	    /* set the size value to the size of this block and mask off to a
+	       256K increment */
+	    u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
+	    if (size > 0)
+		if (bi.num_memory < NUM_MEMINFO) {
+		    /* record the start and size */
+		    bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
+		    bi.memory[bi.num_memory].size = size;
+		    /* count this block */
+		    bi.num_memory++;
+		} else
+		    Printf("Warning: too many memory blocks. Ignoring block "
+			   "of %ldK at 0x%08x\n", size>>10,
+			   (u_long)mh.mh_Lower);
+	} else if (mh.mh_Attributes & MEMF_CHIP)
+	    /* if CHIP memory, record the size */
+	    bi.bi_amiga.chip_size = (u_long)mh.mh_Upper;
+    }
+
+    /* get info from ExecBase */
+    bi.bi_amiga.vblank = SysBase->VBlankFrequency;
+    bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
+    bi.bi_amiga.eclock = SysBase->ex_EClockFrequency;
+
+    /* copy command line options into the kernel command line */
+    strncpy(bi.command_line, commandline, CL_SIZE);
+    bi.command_line[CL_SIZE-1] = '\0';
+
+
+    /* modify the bootinfo, e.g. to change the memory configuration */
+    if (ModifyBootinfo && !ModifyBootinfo(&bi))
+	goto Fail;
+
+
+    /* display Amiga model */
+    if (bi.bi_amiga.model >= first_amiga_model &&
+	bi.bi_amiga.model <= last_amiga_model)
+	Printf("%s ", amiga_models[bi.bi_amiga.model-first_amiga_model]);
+    else
+	Puts("Amiga ");
+
+    /* display the CPU type */
+    Puts("CPU: ");
+    switch (bi.cputype & CPU_MASK) {
+	case CPU_68020:
+	    Puts("68020 (Do you have an MMU?)");
+	    break;
+	case CPU_68030:
+	    Puts("68030");
+	    break;
+	case CPU_68040:
+	    Puts("68040");
+	    break;
+	case CPU_68060:
+	    Puts("68060");
+	    break;
+	default:
+	    Puts("Insufficient for Linux.  Aborting...\n");
+	    Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
+	    goto Fail;
+    }
+    switch (bi.cputype & ~CPU_MASK) {
+	case FPU_68881:
+	    Puts(" with 68881 FPU");
+	    break;
+	case FPU_68882:
+	    Puts(" with 68882 FPU");
+	    break;
+	case FPU_68040:
+	case FPU_68060:
+	    Puts(" with internal FPU");
+	    break;
+	default:
+	    Puts(" without FPU");
+	    break;
+    }
+
+    /* display the chipset */
+    switch(bi.bi_amiga.chipset) {
+	case CS_STONEAGE:
+	    Puts(", old or unknown chipset");
+	    break;
+	case CS_OCS:
+	    Puts(", OCS");
+	    break;
+	case CS_ECS:
+	    Puts(", ECS");
+	    break;
+	case CS_AGA:
+	    Puts(", AGA chipset");
+	    break;
+    }
+
+    Puts("\n\n");
+
+    /* display the command line */
+    Printf("Command line is '%s'\n", bi.command_line);
+
+    /* display the clock statistics */
+    Printf("Vertical Blank Frequency: %ldHz\n", bi.bi_amiga.vblank);
+    Printf("Power Supply Frequency: %ldHz\n", bi.bi_amiga.psfreq);
+    Printf("EClock Frequency: %ldHz\n\n", bi.bi_amiga.eclock);
+
+    /* display autoconfig devices */
+    if (bi.bi_amiga.num_autocon) {
+	Printf("Found %ld AutoConfig Device%s\n", bi.bi_amiga.num_autocon,
+	       bi.bi_amiga.num_autocon > 1 ? "s" : "");
+	for (i = 0; i < bi.bi_amiga.num_autocon; i++) {
+	    Printf("Device %ld: addr = 0x%08lx", i,
+		   (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
+	    boardresetfuncs[i] = NULL;
+	    if (reset_boards) {
+		manuf = bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
+		prod = bi.bi_amiga.autocon[i].cd_Rom.er_Product;
+		for (j = 0; j < NUM_BOARDRESET; j++)
+		    if ((manuf == boardresetdb[j].manuf) &&
+			(prod == boardresetdb[j].prod)) {
+			Printf(" [%s - will be reset at kernel boot time]",
+			       boardresetdb[j].name);
+			boardresetfuncs[i] = boardresetdb[j].reset;
+			break;
+		    }
+	    }
+	    PutChar('\n');
+	}
+    } else
+	Puts("No AutoConfig Devices Found\n");
+
+    /* display memory */
+    if (bi.num_memory) {
+	Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
+	       bi.num_memory > 1 ? "s " : " ");
+	for (i = 0; i < bi.num_memory; i++)
+	    Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
+		   bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
+		   bi.memory[i].size>>10);
+    } else {
+	Puts("No memory found?!  Aborting...\n");
+	goto Fail;
+    }
+
+    /* display chip memory size */
+    Printf("%ldK of CHIP memory\n", bi.bi_amiga.chip_size>>10);
+
+    start_mem = bi.memory[0].addr;
+    mem_size = bi.memory[0].size;
+
+    /* tell us where the kernel will go */
+    Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
+
+    /* verify that there is enough Chip RAM */
+    if (bi.bi_amiga.chip_size < 512*1024) {
+	Puts("Not enough Chip RAM in this system.  Aborting...\n");
+	goto Fail;
+    }
+
+    /* verify that there is enough Fast RAM */
+    for (fast_total = 0, i = 0; i < bi.num_memory; i++)
+	fast_total += bi.memory[i].size;
+    if (fast_total < 2*1024*1024) {
+	Puts("Not enough Fast RAM in this system.  Aborting...\n");
+	goto Fail;
+    }
+
+    /* support for ramdisk */
+    if (ramdiskname) {
+	int size;
+
+	if ((size = FileSize(ramdiskname)) == -1) {
+	    Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
+	    goto Fail;
+	}
+	/* record ramdisk size */
+	bi.ramdisk_size = (size+1023)>>10;
+    } else
+	bi.ramdisk_size = 0;
+    rd_size = bi.ramdisk_size<<10;
+    bi.ramdisk_addr = start_mem+mem_size-rd_size;
+
+    /* open kernel executable and read exec header */
+    if ((kfd = Open(kernelname)) == -1) {
+	Printf("Unable to open kernel file `%s'\n", kernelname);
+	goto Fail;
+    }
+    if (Read(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
+	Puts("Unable to read exec header from kernel file\n");
+	goto Fail;
+    }
+
+    switch (N_MAGIC(kexec)) {
+	case ZMAGIC:
+	    if (debugflag)
+		Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
+	    text_offset = N_TXTOFF(kexec);
+	    break;
+
+	case QMAGIC:
+	    if (debugflag)
+		Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
+	    text_offset = sizeof(kexec);
+	    /* the text size includes the exec header; remove this */
+	    kexec.a_text -= sizeof(kexec);
+	    break;
+
+	default:
+	    /* Try to parse it as an ELF header */
+	    Seek(kfd, 0);
+	    if ((Read(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
+		 sizeof(kexec_elf)) &&
+		 (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
+		elf_kernel = 1;
+		if (debugflag)
+		    Puts("\nLoading ELF Linux/m68k kernel...\n");
+		/* A few plausibility checks */
+		if ((kexec_elf.e_type != ET_EXEC) ||
+		    (kexec_elf.e_machine != EM_68K) ||
+		    (kexec_elf.e_version != EV_CURRENT)) {
+		    Puts("Invalid ELF header contents in kernel\n");
+		    goto Fail;
+		}
+		/* Load the program headers */
+		if (!(kernel_phdrs =
+		      (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
+					     MEMF_FAST | MEMF_PUBLIC |
+					     MEMF_CLEAR))) {
+		    Puts("Unable to allocate memory for program headers\n");
+		    goto Fail;
+		}
+		Seek(kfd, kexec_elf.e_phoff);
+		if (Read(kfd, (void *)kernel_phdrs,
+			 kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
+		    kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
+		    Puts("Unable to read program headers from kernel file\n");
+		    goto Fail;
+		}
+		break;
+	    }
+	    Printf("Wrong magic number 0x%08lx in kernel header\n",
+		   N_MAGIC(kexec));
+	    goto Fail;
+    }
+
+    /* Load the kernel at one page after start of mem */
+    start_mem += PAGE_SIZE;
+    mem_size -= PAGE_SIZE;
+    /* Align bss size to multiple of four */
+    if (!elf_kernel)
+	kexec.a_bss = (kexec.a_bss+3) & ~3;
+
+    /* calculate the total required amount of memory */
+    if (elf_kernel) {
+	u_long min_addr = 0xffffffff, max_addr = 0;
+	for (i = 0; i < kexec_elf.e_phnum; i++) {
+	    if (min_addr > kernel_phdrs[i].p_vaddr)
+		min_addr = kernel_phdrs[i].p_vaddr;
+	    if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
+		max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
+	}
+	/* This is needed for newer linkers that include the header in
+	   the first segment.  */
+	if (min_addr == 0) {
+	    min_addr = PAGE_SIZE;
+	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
+	    kernel_phdrs[0].p_offset += PAGE_SIZE;
+	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
+	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
+	}
+	kernel_size = max_addr-min_addr;
+    } else
+	kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
+    memreq = kernel_size+sizeof(struct bootinfo)+rd_size;
+    if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
+					    MEMF_CLEAR))) {
+	Puts("Unable to allocate memory\n");
+	goto Fail;
+    }
+
+    /* read the text and data segments from the kernel image */
+    if (elf_kernel)
+	for (i = 0; i < kexec_elf.e_phnum; i++) {
+	    if (Seek(kfd, kernel_phdrs[i].p_offset) == -1) {
+		Printf("Failed to seek to segment %ld\n", i);
+		goto Fail;
+	    }
+	    if (Read(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
+		     kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
+		Printf("Failed to read segment %ld\n", i);
+		goto Fail;
+	    }
+	}
+    else {
+	if (Seek(kfd, text_offset) == -1) {
+	    Printf("Failed to seek to text\n");
+	    goto Fail;
+	}
+	if (Read(kfd, memptr, kexec.a_text) != kexec.a_text) {
+	    Printf("Failed to read text\n");
+	    goto Fail;
+	}
+	/* data follows immediately after text */
+	if (Read(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
+	    Printf("Failed to read data\n");
+	    goto Fail;
+	}
+    }
+    Close(kfd);
+    kfd = -1;
+
+    /* Check kernel's bootinfo version */
+    if (!check_bootinfo_version(memptr))
+	goto Fail;
+
+    /* copy the bootinfo to the end of the kernel image */
+    memcpy((void *)(memptr+kernel_size), &bi, sizeof(struct bootinfo));
+
+    if (ramdiskname) {
+	if ((rfd = Open(ramdiskname)) == -1) {
+	    Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
+	    goto Fail;
+	}
+	if (Read(rfd, memptr+kernel_size+sizeof(bi), rd_size) != rd_size) {
+	    Printf("Failed to read ramdisk file\n");
+	    goto Fail;
+	}
+	Close(rfd);
+	rfd = -1;
+    }
+
+    /* allocate temporary chip ram stack */
+    if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
+	Puts("Unable to allocate memory for stack\n");
+	goto Fail;
+    }
+
+    /* allocate chip ram for copy of startup code */
+    startcodesize = &copyallend-&copyall;
+    if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
+					       MEMF_CHIP | MEMF_CLEAR))) {
+	Puts("Unable to allocate memory for startcode\n");
+	goto Fail;
+    }
+
+    /* copy startup code to CHIP RAM */
+    memcpy(startfunc, &copyall, startcodesize);
+
+    if (debugflag) {
+	if (bi.ramdisk_size)
+	    Printf("RAM disk at 0x%08lx, size is %ldK\n",
+		   (u_long)memptr+kernel_size, bi.ramdisk_size);
+
+	if (elf_kernel) {
+	    PutChar('\n');
+	    for (i = 0; i < kexec_elf.e_phnum; i++)
+		Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
+		       start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
+		       kernel_phdrs[i].p_memsz);
+	    Printf("Boot info        at 0x%08lx\n", start_mem+kernel_size);
+	} else {
+	    Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
+		   kexec.a_text);
+	    Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
+		   start_mem+kexec.a_text, kexec.a_data);
+	    Printf("Kernel bss  at 0x%08lx, bss  size 0x%08lx\n",
+		   start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
+	    Printf("Boot info   at 0x%08lx\n", start_mem+kernel_size);
+	}
+	Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
+							   kexec.a_entry);
+
+	Printf("ramdisk dest top is 0x%08lx\n", start_mem+mem_size);
+	Printf("ramdisk lower limit is 0x%08lx\n", (u_long)memptr+kernel_size);
+	Printf("ramdisk src top is 0x%08lx\n",
+	       (u_long)memptr+kernel_size+rd_size);
+
+	Puts("\nType a key to continue the Linux/m68k boot...");
+	GetChar();
+	PutChar('\n');
+    }
+
+    /* wait for things to settle down */
+    Sleep(1000000);
+
+    if (!keep_video)
+	/* set graphics mode to a nice normal one */
+	LoadView(NULL);
+
+    Disable();
+
+    /* reset nasty Zorro boards */
+    if (reset_boards)
+	for (i = 0; i < bi.bi_amiga.num_autocon; i++)
+	    if (boardresetfuncs[i])
+		boardresetfuncs[i](&bi.bi_amiga.autocon[i]);
+
+    /* Turn off all DMA */
+    custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+    /* turn off caches */
+    CacheControl(0, ~0);
+
+    /* Go into supervisor state */
+    SuperState();
+
+    /* turn off any mmu translation */
+    disable_mmu();
+
+    /* execute the copy-and-go code (from CHIP RAM) */
+    start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
+		 mem_size, rd_size, kernel_size);
+
+    /* Clean up and exit in case of a failure */
+Fail:
+    if (kfd != -1)
+	Close(kfd);
+    if (rfd != -1)
+	Close(rfd);
+    if (memptr)
+	FreeMem((void *)memptr, memreq);
+    if (stack)
+	FreeMem((void *)stack, TEMP_STACKSIZE);
+    if (kernel_phdrs)
+	FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
+    return(FALSE);
+}
+
+
+    /*
+     *	Determine the Chipset
+     */
+
+static u_long get_chipset(void)
+{
+    u_char cs;
+    u_long chipset;
+
+    if (GfxBase->Version >= 39)
+	cs = SetChipRev(SETCHIPREV_BEST);
+    else
+	cs = GfxBase->ChipRevBits0;
+    if ((cs & GFXG_AGA) == GFXG_AGA)
+	chipset = CS_AGA;
+    else if ((cs & GFXG_ECS) == GFXG_ECS)
+	chipset = CS_ECS;
+    else if ((cs & GFXG_OCS) == GFXG_OCS)
+	chipset = CS_OCS;
+    else
+	chipset = CS_STONEAGE;
+    return(chipset);
+}
+
+
+    /*
+     *	Determine the CPU Type
+     */
+
+static u_long get_cpu(void)
+{
+    u_long cpu = 0;
+
+    if (SysBase->AttnFlags & AFF_68060) {
+	cpu = CPU_68060;
+	if (SysBase->AttnFlags & AFF_FPU40)
+	    cpu |= FPU_68060;
+    } else if (SysBase->AttnFlags & AFF_68040) {
+	cpu = CPU_68040;
+	if (SysBase->AttnFlags & AFF_FPU40)
+	    cpu |= FPU_68040;
+    } else {
+	if (SysBase->AttnFlags & AFF_68030)
+	    cpu = CPU_68030;
+	else if (SysBase->AttnFlags & AFF_68020)
+	    cpu = CPU_68020;
+	if (SysBase->AttnFlags & AFF_68882)
+	    cpu |= FPU_68882;
+	else if (SysBase->AttnFlags & AFF_68881)
+	    cpu |= FPU_68881;
+    }
+    return(cpu);
+}
+
+
+    /*
+     *	Determine the Amiga Model
+     */
+
+static u_long get_model(u_long chipset)
+{
+    u_long model = AMI_UNKNOWN;
+
+    if (debugflag)
+	Puts("Amiga model identification:\n");
+    if (probe_resource("draco.resource"))
+	model = AMI_DRACO;
+    else {
+	if (debugflag)
+	    Puts("    Chipset: ");
+	switch(chipset) {
+	    case CS_STONEAGE:
+		if (debugflag)
+		    Puts("Old or unknown\n");
+		goto OCS;
+		break;
+
+	    case CS_OCS:
+		if (debugflag)
+		    Puts("OCS\n");
+OCS:		if (probe_resident("cd.device"))
+		    model = AMI_CDTV;
+		else
+		    /* let's call it an A2000 (may be A500, A1000, A2500) */
+		    model = AMI_2000;
+		break;
+
+	    case CS_ECS:
+		if (debugflag)
+		    Puts("ECS\n");
+		if (probe_resident("Magic 36.7") ||
+		    probe_resident("kickad 36.57") ||
+		    probe_resident("A3000 Bonus") ||
+		    probe_resident("A3000 bonus"))
+		    /* let's call it an A3000 (may be A3000T) */
+		    model = AMI_3000;
+		else if (probe_resource("card.resource"))
+		    model = AMI_600;
+		else
+		    /* let's call it an A2000 (may be A500[+], A1000, A2500) */
+		    model = AMI_2000;
+		break;
+
+	    case CS_AGA:
+		if (debugflag)
+		    Puts("AGA\n");
+		if (probe_resident("A1000 Bonus") ||
+		    probe_resident("A4000 bonus"))
+		    model = probe_resident("NCR scsi.device") ? AMI_4000T :
+								AMI_4000;
+		else if (probe_resource("card.resource"))
+		    model = AMI_1200;
+		else if (probe_resident("cd.device"))
+		    model = AMI_CD32;
+		else
+		    model = AMI_3000PLUS;
+		break;
+	}
+    }
+    if (debugflag) {
+	Puts("\nType a key to continue...");
+	GetChar();
+	Puts("\n\n");
+    }
+    return(model);
+}
+
+
+    /*
+     *	Probe for a Resident Modules
+     */
+
+static int probe_resident(const char *name)
+{
+    const struct Resident *res;
+
+    if (debugflag)
+	Printf("    Module `%s': ", name);
+    res = FindResident(name);
+    if (debugflag)
+	if (res)
+	    Printf("0x%08lx\n", res);
+	else
+	    Printf("not present\n");
+    return(res ? TRUE : FALSE);
+}
+
+
+    /*
+     *	Probe for an available Resource
+     */
+
+static int probe_resource(const char *name)
+{
+    const void *res;
+
+    if (debugflag)
+	Printf("    Resource `%s': ", name);
+    res = OpenResource(name);
+    if (debugflag)
+	if (res)
+	    Printf("0x%08lx\n", res);
+	else
+	    Printf("not present\n");
+    return(res ? TRUE : FALSE);
+}
+
+
+    /*
+     *  Compare the Bootstrap and Kernel Versions
+     */
+
+static int check_bootinfo_version(const char *memptr)
+{
+    const struct bootversion *bv = (struct bootversion *)memptr;
+    unsigned long version = 0;
+    int i, kernel_major, kernel_minor, boots_major, boots_minor;
+
+    if (bv->magic == BOOTINFOV_MAGIC)
+	for (i = 0; bv->machversions[i].machtype != 0; ++i)
+	    if (bv->machversions[i].machtype == MACH_AMIGA) {
+		version = bv->machversions[i].version;
+		break;
+	    }
+    if (!version)
+	Printf("Kernel has no bootinfo version info, assuming 0.0\n");
+
+    kernel_major = BI_VERSION_MAJOR(version);
+    kernel_minor = BI_VERSION_MINOR(version);
+    boots_major  = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
+    boots_minor  = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
+    Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
+	   boots_minor);
+    Printf("Kernel's bootinfo version   : %ld.%ld\n", kernel_major,
+	   kernel_minor);
+
+    if (kernel_major != boots_major) {
+	Printf("\nThis bootstrap is too %s for this kernel!\n",
+	       boots_major < kernel_major ? "old" : "new");
+	return(0);
+    }
+    if (kernel_minor > boots_minor) {
+	Printf("Warning: Bootinfo version of bootstrap and kernel differ!\n" );
+	Printf("         Certain features may not work.\n");
+    }
+    return(1);
+}
+
+
+    /*
+     *	Call the copy-and-go-code
+     */
+
+static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
+			 u_long start_mem, u_long mem_size, u_long rd_size,
+			 u_long kernel_size)
+{
+    register void (*a0)() __asm("a0") = startfunc;
+    register char *a2 __asm("a2") = stackp;
+    register char *a3 __asm("a3") = memptr;
+    register u_long a4 __asm("a4") = start_mem;
+    register u_long d0 __asm("d0") = mem_size;
+    register u_long d1 __asm("d1") = rd_size;
+    register u_long d2 __asm("d2") = kernel_size;
+    register u_long d3 __asm("d3") = sizeof(struct bootinfo);
+
+    __asm __volatile ("movel a2,sp;"
+		      "jmp a0@"
+		      : /* no outputs */
+		      : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
+			"r" (d1), "r" (d2), "r" (d3)
+		      /* no return */);
+    /* fake a noreturn */
+    for (;;);
+}
+
+
+    /*
+     *	This assembler code is copied to chip ram, and then executed.
+     *	It copies the kernel to it's final resting place.
+     *
+     *	It is called with:
+     *
+     *	    a3 = memptr
+     *	    a4 = start_mem
+     *	    d0 = mem_size
+     *	    d1 = rd_size
+     *	    d2 = kernel_size
+     *	    d3 = sizeof(struct bootinfo)
+     */
+
+asm(".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(copyall) ":
+				| /* copy kernel text and data */
+	movel	a3,a0		| src = (u_long *)memptr;
+	movel	a0,a2		| limit = (u_long *)(memptr+kernel_size);
+	addl	d2,a2
+	movel	a4,a1		| dest = (u_long *)start_mem;
+1:	cmpl	a0,a2
+	jeq	2f		| while (src < limit)
+	moveb	a0@+,a1@+	|  *dest++ = *src++;
+	jra	1b
+2:
+				| /* copy early bootinfo to end of bss */
+	movel	a3,a0		| src = (u_long *)(memptr+kernel_size);
+	addl	d2,a0		| dest = end of bss (already in a1)
+	movel	d3,d7		| count = sizeof(struct bootinfo)
+	subql	#1,d7
+1:	moveb	a0@+,a1@+	| while (--count > -1)
+	dbra	d7,1b		|     *dest++ = *src++
+
+				| /* copy the ramdisk to the top of memory */
+				| /* (from back to front) */
+	movel	a4,a1		| dest = (u_long *)(start_mem+mem_size);
+	addl	d0,a1
+	movel	a3,a2		| limit = (u_long *)(memptr+kernel_size +
+	addl	d2,a2		|		     sizeof(struct bootinfo));
+	addl	d3,a2
+	movel	a2,a0		| src = (u_long *)((u_long)limit+rd_size);
+	addl	d1,a0
+1:	cmpl	a0,a2
+	beqs	2f		| while (src > limit)
+	moveb	a0@-,a1@-	|     *--dest = *--src;
+	bras	1b
+2:
+				| /* jump to start of kernel */
+	movel	a4,a0		| jump_to (start_mem);
+	jmp	a0@
+"
+SYMBOL_NAME_STR(copyallend) ":
+");
+
+
+    /*
+     *	Test for a MapROMmed A3640 Board
+     */
+
+asm(".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(maprommed) ":
+	oriw	#0x0700,sr
+	moveml	#0x3f20,sp@-
+				| /* Save cache settings */
+	.long	0x4e7a1002	| movec cacr,d1 */
+				| /* Save MMU settings */
+	.long	0x4e7a2003	| movec tc,d2
+	.long	0x4e7a3004	| movec itt0,d3
+	.long	0x4e7a4005	| movec itt1,d4
+	.long	0x4e7a5006	| movec dtt0,d5
+	.long	0x4e7a6007	| movec dtt1,d6
+	moveq	#0,d0
+	movel	d0,a2
+				| /* Disable caches */
+	.long	0x4e7b0002	| movec d0,cacr
+				| /* Disable MMU */
+	.long	0x4e7b0003	| movec d0,tc
+	.long	0x4e7b0004	| movec d0,itt0
+	.long	0x4e7b0005	| movec d0,itt1
+	.long	0x4e7b0006	| movec d0,dtt0
+	.long	0x4e7b0007	| movec d0,dtt1
+	lea	0x07f80000,a0
+	lea	0x00f80000,a1
+	movel	a0@,d7
+	cmpl	a1@,d7
+	jne	1f
+	movel	d7,d0
+	notl	d0
+	movel	d0,a0@
+	nop			| /* Thanks to Jörg Mayer! */
+	cmpl	a1@,d0
+	jne	1f
+	moveq	#-1,d0		| /* MapROMmed A3640 present */
+	movel	d0,a2
+1:	movel	d7,a0@
+				| /* Restore MMU settings */
+	.long	0x4e7b2003	| movec d2,tc
+	.long	0x4e7b3004	| movec d3,itt0
+	.long	0x4e7b4005	| movec d4,itt1
+	.long	0x4e7b5006	| movec d5,dtt0
+	.long	0x4e7b6007	| movec d6,dtt1
+				| /* Restore cache settings */
+	.long	0x4e7b1002	| movec d1,cacr
+	movel	a2,d0
+	moveml	sp@+,#0x04fc
+	rte
+");
+
+
+    /*
+     *	Reset functions for nasty Zorro boards
+     */
+
+static void reset_rb3(const struct ConfigDev *cd)
+{
+    volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
+
+    /* FN: If a Rainbow III board is present, reset it to disable */
+    /* its (possibly activated) vertical blank interrupts as the */
+    /* kernel is not yet prepared to handle them (level 6). */
+
+    /* set RESET bit in special function register */
+    *rb3_reg = 0x01;
+    /* actually, only a few cycles delay are required... */
+    Sleep(1000000);
+    /* clear reset bit */
+    *rb3_reg = 0x00;
+}
+
+static void reset_piccolo(const struct ConfigDev *cd)
+{
+    volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
+
+    /* FN: the same stuff as above, for the Piccolo board. */
+    /* this also has the side effect of resetting the board's */
+    /* output selection logic to use the Amiga's display in single */
+    /* monitor systems - which is currently what we want. */
+
+    /* set RESET bit in special function register */
+    *piccolo_reg = 0x01;
+    /* actually, only a few cycles delay are required... */
+    Sleep(1000000);
+    /* clear reset bit */
+    *piccolo_reg = 0x51;
+}
+
+static void reset_sd64(const struct ConfigDev *cd)
+{
+    volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
+
+    /* FN: the same stuff as above, for the SD64 board. */
+    /* just as on the Piccolo, this also resets the monitor switch */
+
+    /* set RESET bit in special function register */
+    *sd64_reg = 0x1f;
+    /* actually, only a few cycles delay are required... */
+    Sleep(1000000);
+    /* clear reset bit AND switch monitor bit (0x20) */
+    *sd64_reg = 0x4f;
+}
+
+static void reset_ariadne(const struct ConfigDev *cd)
+{
+    volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
+    volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
+    volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
+
+    volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
+    volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
+    volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
+    volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
+    volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
+
+    u_short in;
+
+    Disable();
+
+    /*
+     *	Reset the Ethernet part (Am79C960 PCnet-ISA)
+     */
+
+    in = *lance_reset;   /* Reset Chip on Read Access */
+    *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
+    *lance_rdp = 0x0400; /* STOP */
+
+    /*
+     *	Reset the Parallel part (MC68230 PI/T)
+     */
+
+    *pit_pacr &= 0xfd;   /* Port A Control Register */
+    *pit_pbcr &= 0xfd;   /* Port B Control Register */
+    *pit_psr = 0x05;     /* Port Status Register */
+    *pit_paddr = 0x00;   /* Port A Data Direction Register */
+    *pit_pbddr = 0x00;   /* Port B Data Direction Register */
+
+    Enable();
+}
+
+static void reset_hydra(const struct ConfigDev *cd)
+{
+    volatile u_char *nic_cr  = (u_char *)(cd->cd_BoardAddr+0xffe1);
+    volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
+    int n = 5000;
+
+    Disable();
+ 
+    *nic_cr = 0x21;	/* nic command register: software reset etc. */
+    while(((*nic_isr & 0x80) == 0) && --n)  /* wait for reset to complete */
+	;
+ 
+    Enable();
+}
+
+#if 0
+static void reset_a2060(const struct ConfigDev *cd)
+{
+#error reset_a2060: not yet implemented
+}
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/linuxboot.h linux/arch/m68k/boot/amiga/linuxboot.h
--- lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/linuxboot.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/amiga/linuxboot.h	Wed Sep 25 10:47:39 1996
@@ -0,0 +1,427 @@
+/*
+ *  linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
+ *					      on Amiga, used by both Amiboot and
+ *					      Amiga-Lilo.
+ *
+ *	Created 1996 by Geert Uytterhoeven
+ *
+ *
+ *  This file is based on the original bootstrap code (bootstrap.c):
+ *
+ *	Copyright (C) 1993, 1994 Hamish Macdonald
+ *				 Greg Harp
+ *
+ *		    with work by Michael Rausch
+ *				 Geert Uytterhoeven
+ *				 Frank Neumann
+ *				 Andreas Schwab
+ *
+ *
+ *  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 <asm/setup.h>
+#include <asm/zorro.h>
+
+
+    /*
+     *  Amiboot Version
+     */
+
+#define AMIBOOT_VERSION		"4.0"
+
+
+    /*
+     *  Parameters passed to linuxboot()
+     */
+
+struct linuxboot_args {
+    const char *kernelname;
+    const char *ramdiskname;
+    const char *commandline;
+    int debugflag;
+    int keep_video;
+    int reset_boards;
+    void (*puts)(const char *str);
+    long (*getchar)(void);
+    void (*putchar)(char c);
+    void (*printf)(const char *fmt, ...);
+    int (*open)(const char *path);
+    int (*seek)(int fd, int offset);
+    int (*read)(int fd, char *buf, int count);
+    void (*close)(int fd);
+    int (*filesize)(const char *path);
+    void (*sleep)(u_long micros);
+    int (*modify_bootinfo)(struct bootinfo *bi);
+};
+
+
+    /*
+     *  Boot the Linux/m68k Operating System
+     */
+
+extern u_long linuxboot(const struct linuxboot_args *args);
+
+
+    /*
+     *  Amiga Models
+     */
+
+extern const char *amiga_models[];
+extern const u_long first_amiga_model;
+extern const u_long last_amiga_model;
+
+
+    /*
+     *	Exec Library Definitions
+     */
+
+#define TRUE	(1)
+#define FALSE	(0)
+
+
+struct List {
+    struct Node *lh_Head;
+    struct Node *lh_Tail;
+    struct Node *lh_TailPred;
+    u_char lh_Type;
+    u_char l_pad;
+};
+
+struct MemChunk {
+     struct MemChunk *mc_Next;	/* pointer to next chunk */
+     u_long mc_Bytes;		/* chunk byte size    */
+};
+
+#define MEMF_PUBLIC	(1<<0)
+#define MEMF_CHIP	(1<<1)
+#define MEMF_FAST	(1<<2)
+#define MEMF_LOCAL	(1<<8)
+#define MEMF_CLEAR	(1<<16)
+
+struct MemHeader {
+    struct Node mh_Node;
+    u_short mh_Attributes;	/* characteristics of this region */
+    struct MemChunk *mh_First;	/* first free region */
+    void *mh_Lower;		/* lower memory bound */
+    void *mh_Upper;		/* upper memory bound+1 */
+    u_long mh_Free;		/* total number of free bytes */
+};
+
+struct ExecBase {
+    u_char fill1[20];
+    u_short Version;
+    u_char fill2[274];
+    u_short AttnFlags;
+    u_char fill3[24];
+    struct List MemList;
+    u_char fill4[194];
+    u_char VBlankFrequency;
+    u_char PowerSupplyFrequency;
+    u_char fill5[36];
+    u_long ex_EClockFrequency;
+    u_char fill6[60];
+};
+
+#define AFB_68020	(1)
+#define AFF_68020	(1<<AFB_68020)
+#define AFB_68030	(2)
+#define AFF_68030	(1<<AFB_68030)
+#define AFB_68040	(3)
+#define AFF_68040	(1<<AFB_68040)
+#define AFB_68881	(4)
+#define AFF_68881	(1<<AFB_68881)
+#define AFB_68882	(5)
+#define AFF_68882	(1<<AFB_68882)
+#define AFB_FPU40	(6)		/* ONLY valid if AFB_68040 or AFB_68060 */
+#define AFF_FPU40	(1<<AFB_FPU40)	/* is set; also set for 68060 FPU */
+#define AFB_68060	(7)
+#define AFF_68060	(1<<AFB_68060)
+
+struct Resident;
+
+
+    /*
+     *	Graphics Library Definitions
+     */
+
+struct GfxBase {
+    u_char fill1[20];
+    u_short Version;
+    u_char fill2[194];
+    u_short NormalDisplayRows;
+    u_short NormalDisplayColumns;
+    u_char fill3[16];
+    u_char ChipRevBits0;
+    u_char fill4[307];
+};
+
+#define GFXB_HR_AGNUS	(0)
+#define GFXF_HR_AGNUS	(1<<GFXB_HR_AGNUS)
+#define GFXB_HR_DENISE	(1)
+#define GFXF_HR_DENISE	(1<<GFXB_HR_DENISE)
+#define GFXB_AA_ALICE	(2)
+#define GFXF_AA_ALICE	(1<<GFXB_AA_ALICE)
+#define GFXB_AA_LISA	(3)
+#define GFXF_AA_LISA	(1<<GFXB_AA_LISA)
+
+    /*
+     *	HiRes(=Big) Agnus present; i.e. 
+     *	1MB chipmem, big blits (none of interest so far) and programmable sync
+     */
+#define GFXG_OCS	(GFXF_HR_AGNUS)
+    /*
+     *	HiRes Agnus/Denise present; we are running on ECS
+     */
+#define GFXG_ECS	(GFXF_HR_AGNUS|GFXF_HR_DENISE)
+    /*
+     *	Alice and Lisa present; we are running on AGA
+     */
+#define GFXG_AGA	(GFXF_AA_ALICE|GFXF_AA_LISA)
+
+#define SETCHIPREV_BEST	(0xffffffff)
+#define HIRES		(0x8000)
+
+struct View;
+
+
+    /*
+     *	Amiga Shared Library/Device Functions
+     */
+
+extern const struct ExecBase *SysBase;
+
+#define LVOAllocMem		(-0xc6)
+#define LVOAllocVec		(-0x2ac)
+#define LVOCacheControl		(-0x288)
+#define LVODisable		(-0x78)
+#define LVOEnable		(-0x7e)
+#define LVOFindResident		(-0x60)
+#define LVOFreeMem		(-0xd2)
+#define LVOFreeVec		(-0x2b2)
+#define LVOOpenresource		(-0x1f2)
+#define LVOSuperState		(-0x96)
+#define LVOSupervisor		(-0x1e)
+
+static __inline void *AllocMem(u_long byteSize, u_long requirements)
+{
+    register void *_res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register u_long d0 __asm("d0") = byteSize;
+    register u_long d1 __asm("d1") = requirements;
+
+    __asm __volatile ("jsr a6@(-0xc6)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (d0), "r" (d1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+static __inline void *AllocVec(u_long byteSize, u_long requirements)
+{
+    register void *_res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register u_long d0 __asm("d0") = byteSize;
+    register u_long d1 __asm("d1") = requirements;
+
+    __asm __volatile ("jsr a6@(-0x2ac)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (d0), "r" (d1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
+{
+    register u_long _res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register u_long d0 __asm("d0") = cacheBits;
+    register u_long d1 __asm("d1") = cacheMask;
+
+    __asm __volatile ("jsr a6@(-0x288)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (d0), "r" (d1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+static __inline void Disable(void)
+{
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+
+    __asm __volatile ("jsr a6@(-0x78)"
+		      : /* no output */
+		      : "r" (_base)
+		      : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void Enable(void)
+{
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+
+    __asm __volatile ("jsr a6@(-0x7e)"
+		      : /* no output */
+		      : "r" (_base)
+		      : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline struct Resident *FindResident(const u_char *name)
+{
+    register struct Resident *_res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register const u_char *a1 __asm("a1") = name;
+
+    __asm __volatile ("jsr a6@(-0x60)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (a1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return _res;
+}
+
+static __inline void FreeMem(void *memoryBlock, u_long byteSize)
+{
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register void *a1 __asm("a1") = memoryBlock;
+    register u_long d0 __asm("d0") = byteSize;
+
+    __asm __volatile ("jsr a6@(-0xd2)"
+		      : /* no output */
+		      : "r" (_base), "r" (a1), "r" (d0)
+		      : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void FreeVec(void *memoryBlock)
+{
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register void *a1 __asm("a1") = memoryBlock;
+
+    __asm __volatile ("jsr a6@(-0x2b2)"
+		      : /* no output */
+		      : "r" (_base), "r" (a1)
+		      : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline void *OpenResource(const u_char *resName)
+{
+    register void *_res  __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register const u_char *a1 __asm("a1") = resName;
+
+    __asm __volatile ("jsr a6@(-0x1f2)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (a1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return _res;
+}
+
+static __inline void *SuperState(void)
+{
+    register void *_res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+
+    __asm __volatile ("jsr a6@(-0x96)"
+		      : "=r" (_res)
+		      : "r" (_base)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+static __inline u_long Supervisor(u_long (*userfunc)(void))
+{
+    register u_long _res __asm("d0");
+    register const struct ExecBase *_base __asm("a6") = SysBase;
+    register u_long (*d7)() __asm("d7") = userfunc;
+
+    __asm __volatile ("exg d7,a5;"
+		      "jsr a6@(-0x1e);"
+		      "exg d7,a5"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (d7)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+
+extern const struct ExpansionBase *ExpansionBase;
+
+#define LVOFindConfigDev	(-0x48)
+
+static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
+						long manufacturer, long product)
+{
+    register struct ConfigDev *_res __asm("d0");
+    register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
+    register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
+    register long d0 __asm("d0") = manufacturer;
+    register long d1 __asm("d1") = product;
+
+    __asm __volatile ("jsr a6@(-0x48)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+
+extern const struct GfxBase *GfxBase;
+
+#define LVOLoadView		(-0xde)
+#define LVOSetChipRev		(-0x378)
+
+static __inline void LoadView(struct View *view)
+{
+    register const struct GfxBase *_base __asm("a6") = GfxBase;
+    register struct View *a1 __asm("a1") = view;
+
+    __asm __volatile ("jsr a6@(-0xde)"
+		      : /* no output */
+		      : "r" (_base), "r" (a1)
+		      : "a0", "a1", "d0", "d1", "memory");
+}
+
+static __inline u_long SetChipRev(u_long want)
+{
+    register u_long _res __asm("d0");
+    register const struct GfxBase *_base __asm("a6") = GfxBase;
+    register u_long d0 __asm("d0") = want;
+
+    __asm __volatile ("jsr a6@(-0x378)"
+		      : "=r" (_res)
+		      : "r" (_base), "r" (d0)
+		      : "a0", "a1", "d0", "d1", "memory");
+    return(_res);
+}
+
+
+    /*
+     *	Bootstrap Support Functions
+     */
+
+static __inline void disable_mmu(void)
+{
+    if (SysBase->AttnFlags & AFF_68040)
+	__asm __volatile ("moveq #0,d0;"
+			  ".long 0x4e7b0003;"	/* movec d0,tc */
+			  ".long 0x4e7b0004;"	/* movec d0,itt0 */
+			  ".long 0x4e7b0005;"	/* movec d0,itt1 */
+			  ".long 0x4e7b0006;"	/* movec d0,dtt0 */
+			  ".long 0x4e7b0007"	/* movec d0,dtt1 */
+			  : /* no outputs */
+			  : /* no inputs */
+			  : "d0");
+    else {
+	__asm __volatile ("subl #4,sp;"
+			  "pmove tc,sp@;"
+			  "bclr #7,sp@;"
+			  "pmove sp@,tc;"
+			  "addl #4,sp");
+	if (SysBase->AttnFlags & AFF_68030)
+	    __asm __volatile ("clrl sp@-;"
+			      ".long 0xf0170800;"	/* pmove sp@,tt0 */
+			      ".long 0xf0170c00;"	/* pmove sp@,tt1 */
+			      "addql #4,sp");
+    }
+}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/Makefile linux/arch/m68k/boot/atari/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/Makefile	Wed Dec 27 22:44:40 1995
+++ linux/arch/m68k/boot/atari/Makefile	Thu Jan  1 02:00:00 1970
@@ -1,12 +0,0 @@
-
-CC		:= d:/gnu/bin/gcc.ttp
-CFLAGS	:= -Wall -O2 -fno-defer-pop -mint -s
-LD		:= d:/gnu/bin/gcc.ttp
-LDFLAGS	:= -mint -D__GNUC__
-
-bootstra.ttp: bootstra.o
-	$(LD) $(LDFLAGS) -o $@ $^
-	prgflags 7 7 $@
-	cp $@ d:/linux
-
-bootstra.o: bootstra.c bootinfo.h
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootp.c linux/arch/m68k/boot/atari/bootp.c
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/bootp.c	Wed Sep 25 10:47:39 1996
@@ -0,0 +1,793 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bootp.h"
+
+
+/* --------------------------------------------------------------------- */
+/*						  Protocol Header Structures					 */
+
+struct etherhdr {
+	HWADDR			dst_addr;
+	HWADDR			src_addr;
+	unsigned short	type;
+};
+
+struct arphdr {
+	unsigned short	hrd;		/* format of hardware address	*/
+	unsigned short	pro;		/* format of protocol address	*/
+	unsigned char	hln;		/* length of hardware address	*/
+	unsigned char	pln;		/* length of protocol address	*/
+	unsigned short	op;			/* ARP opcode (command)			*/
+	unsigned char	addr[0];	/* addresses (var len)			*/
+};
+	
+struct iphdr {
+	unsigned char	version : 4;
+	unsigned char	ihl : 4;
+	unsigned char	tos;
+	unsigned short	tot_len;
+	unsigned short	id;
+	unsigned short	frag_off;
+	unsigned char	ttl;
+	unsigned char	protocol;
+	unsigned short	chksum;
+	IPADDR			src_addr;
+	IPADDR			dst_addr;
+};
+
+struct udphdr {
+	unsigned short	src_port;
+	unsigned short	dst_port;
+	unsigned short	len;
+	unsigned short	chksum;
+};
+
+struct bootp {
+	unsigned char	op;			/* packet opcode type */
+	unsigned char	htype;		/* hardware addr type */
+	unsigned char	hlen;		/* hardware addr length */
+	unsigned char	hops;		/* gateway hops */
+	unsigned long	xid;		/* transaction ID */
+	unsigned short	secs;		/* seconds since boot began */
+	unsigned short	unused;
+	IPADDR			ciaddr;		/* client IP address */
+	IPADDR			yiaddr;		/* 'your' IP address */
+	IPADDR			siaddr;		/* server IP address */
+	IPADDR			giaddr; 	/* gateway IP address */
+	unsigned char	chaddr[16];	/* client hardware address */
+	unsigned char	sname[64];	/* server host name */
+	unsigned char	file[128];	/* boot file name */
+	unsigned char	vend[64];	/* vendor-specific area */
+};
+
+struct tftp_req {
+	unsigned short	opcode;
+	char			name[512];
+};
+
+struct tftp_data {
+	unsigned short	opcode;
+	unsigned short	nr;
+	unsigned char	data[512];
+};
+
+struct tftp_ack {
+	unsigned short	opcode;
+	unsigned short	nr;
+};
+
+struct tftp_error {
+	unsigned short	opcode;
+	unsigned short	errcode;
+	char			str[512];
+};
+
+
+typedef struct {
+	struct etherhdr		ether;
+	struct arphdr		arp;
+} ARP;
+
+typedef struct {
+	struct etherhdr		ether;
+	struct iphdr		ip;
+	struct udphdr		udp;
+} UDP;
+
+#define	UDP_BOOTPS	67
+#define	UDP_BOOTPC	68
+#define	UDP_TFTP	69
+
+typedef struct {
+	struct etherhdr		ether;
+	struct iphdr		ip;
+	struct udphdr		udp;
+	struct bootp		bootp;
+} BOOTP;
+
+#define	BOOTREQUEST		1
+#define	BOOTREPLY		2
+#define	BOOTP_RETRYS	5
+
+typedef struct {
+	struct etherhdr		ether;
+	struct iphdr		ip;
+	struct udphdr		udp;
+	union tftp {
+		unsigned short		opcode;
+		struct tftp_req		req;
+		struct tftp_data	data;
+		struct tftp_ack		ack;
+		struct tftp_error	error;
+	} tftp;
+} TFTP;
+	
+#define	TFTP_RRQ	1
+#define	TFTP_WRQ	2
+#define	TFTP_DATA	3
+#define	TFTP_ACK	4
+#define	TFTP_ERROR	5
+
+
+/* --------------------------------------------------------------------- */
+/*								  Addresses								 */
+
+static HWADDR	MyHwaddr;
+static HWADDR	ServerHwaddr;
+static IPADDR	MyIPaddr;
+static IPADDR	ServerIPaddr;
+
+static IPADDR	IP_Unknown_Addr =   0x00000000;
+static IPADDR	IP_Broadcast_Addr = 0xffffffff;
+static HWADDR 	Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+#define	HZ	200
+#define	_hz_200	(*(volatile unsigned long *)0x4ba)
+
+
+/* --------------------------------------------------------------------- */
+/*								Error Strings							 */
+
+static char *ErrStr[] = {
+	"timeout",
+	"general Ethernet transmit error",
+	"general Ethernet receive error",
+	"Ethernet framing error",
+	"Ethernet overflow error",
+	"Ethernet CRC error"
+};
+
+
+/* --------------------------------------------------------------------- */
+/*						 Kfile Emulation Definitions					 */
+
+#define	KFILE_CHUNK_BITS	16  /* chunk is 64 KB */
+#define	KFILE_CHUNK_SIZE	(1 << KFILE_CHUNK_BITS)
+#define	KFILE_CHUNK_MASK	(KFILE_CHUNK_SIZE-1)
+#define	KFILE_N_CHUNKS		(2*1024*1024/KFILE_CHUNK_SIZE)
+
+char *KFile[KFILE_N_CHUNKS];
+int  KFileSize = 0;
+int	 KFpos = 0;
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static void free_kfile( void );
+static int bootp( char *image_name );
+static int tftp( char *image_name );
+static int udp_send( UDP *pkt, int len, int fromport, int toport );
+static unsigned short ip_checksum( struct iphdr *buf );
+static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
+static void print_ip( IPADDR addr );
+static void print_hw( HWADDR addr );
+static int check_ethif( void );
+static int eth_send( Packet *pkt, int len );
+static int eth_rcv( Packet *pkt, int *len );
+
+/************************* End of Prototypes **************************/
+
+
+
+
+/* --------------------------------------------------------------------- */
+/*						   Interface to bootstrap.c						 */
+
+/* get_remote_kernel():
+ * Perform all necessary steps to get the kernel image
+ * from the boot server. If successfull (retval == 0), subsequent calls to
+ * kread() can access the data.
+ */
+
+int get_remote_kernel( const char *kname /* optional */ )
+
+{	char	image_name[256];
+	
+	/* Check if a Ethernet interface is present and determine the Ethernet
+	 * address */
+	if (check_ethif() < 0) {
+		printf( "No Ethernet interface found -- no remote boot possible.\n" );
+		return( -1 );
+	}
+	
+	/* Do a BOOTP request to find out our IP address and the kernel image's
+	 * name; we also learn the IP and Ethernet address of our server */
+	if (kname)
+		strcpy( image_name, kname );
+	else
+		*image_name = 0;
+	if (bootp( image_name ) < 0)
+		return( -1 );
+	
+	/* Now start a TFTP connection to receive the kernel image */
+	if (tftp( image_name ) < 0)
+		return( -1 );
+
+	return( 0 );
+}
+
+
+/* kread(), klseek(), kclose():
+ * Functions for accessing the received kernel image like with read(),
+ * lseek(), close().
+ */
+
+int kread( int fd, void *buf, unsigned cnt )
+
+{	unsigned done = 0;
+	
+	if (!KFileSize)
+		return( read( fd, buf, cnt ) );
+
+	if (KFpos + cnt > KFileSize)
+		cnt = KFileSize - KFpos;
+	
+	while( cnt > 0 ) {
+		unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
+		unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
+		unsigned n = cnt;
+
+		if (KFpos + n > endchunk)
+			n = endchunk - KFpos;
+		memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
+		cnt -= n;
+		buf += n;
+		done += n;
+		KFpos += n;
+	}
+
+	return( done );
+}
+
+
+int klseek( int fd, int where, int whence )
+
+{
+	if (!KFileSize)
+		return( lseek( fd, where, whence ) );
+
+	switch( whence ) {
+	  case SEEK_SET:
+		KFpos = where;
+		break;
+	  case SEEK_CUR:
+		KFpos += where;
+		break;
+	  case SEEK_END:
+		KFpos = KFileSize + where;
+		break;
+	  default:
+		return( -1 );
+	}
+	if (KFpos < 0) {
+		KFpos = 0;
+		return( -1 );
+	}
+	else if (KFpos > KFileSize) {
+		KFpos = KFileSize;
+		return( -1 );
+	}
+
+	return( KFpos );
+}
+
+
+int kclose( int fd )
+
+{
+	if (!KFileSize)
+		return( close( fd ) );
+
+	free_kfile();
+	return( 0 );
+}
+
+
+static void free_kfile( void )
+
+{	int		i;
+
+	for( i = 0; i < KFILE_N_CHUNKS; ++i )
+		if (KFile[i]) free( KFile[i] );
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/*							   BOOTP Procedure							 */
+
+
+static int bootp( char *image_name )
+
+{	BOOTP	req;
+	Packet	_reply;
+	BOOTP	*reply = (BOOTP *)_reply;
+	static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
+	unsigned long 	starttime, rancopy;
+	int				err, len, retry;
+	
+	memset( (char *)&req, 0, sizeof(req) );
+	/* Now fill in the packet... */
+	req.bootp.op = BOOTREQUEST;
+	req.bootp.htype = 1; /* 10Mb/s Ethernet */
+	req.bootp.hlen = 6;
+	memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
+
+	/* Put in the minimal RFC1497 Magic cookie */
+	memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
+	/* Put the user precified bootfile name in place */
+	memcpy( req.bootp.file, image_name, strlen(image_name)+1);
+
+	starttime = _hz_200;
+	for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
+
+		/* Initialize server addresses and own IP to defaults */
+		ServerIPaddr = IP_Broadcast_Addr;  /* 255.255.255.255 */
+		MyIPaddr     = IP_Unknown_Addr;    /* 0.0.0.0 */
+		memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
+
+		if (retry)
+			sleep( 3 );
+		
+		req.bootp.xid = rancopy = _hz_200;
+		req.bootp.secs = (_hz_200 - starttime) / HZ;
+
+		if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
+							 UDP_BOOTPC, UDP_BOOTPS )) < 0) {
+			printf( "bootp send: %s\n", ErrStr[-err-1] );
+			continue;
+		}
+		
+		if ((err = udp_rcv( (UDP *)reply, &len,
+							UDP_BOOTPS, UDP_BOOTPC )) < 0) {
+			printf( "bootp rcv: %s\n", ErrStr[-err-1] );
+			continue;
+		}
+		if (len < sizeof(struct bootp)) {
+			printf( "received short BOOTP packet (%d bytes)\n", len );
+			continue;
+		}
+
+		if (reply->bootp.xid == rancopy)
+			/* Ok, got the answer */
+			break;
+		printf( "bootp: xid mismatch\n" );
+	}
+	if (retry >= BOOTP_RETRYS) {
+		printf( "No response from a bootp server\n" );
+		return( -1 );
+	}
+	
+	ServerIPaddr = reply->bootp.siaddr;
+	memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
+	printf( "\nBoot server is " );
+	if (strlen(reply->bootp.sname) > 0)
+		printf( "%s, IP ", reply->bootp.sname );
+	print_ip( ServerIPaddr );
+	printf( ", HW address " );
+	print_hw( ServerHwaddr );
+	printf( "\n" );
+
+	MyIPaddr = reply->bootp.yiaddr;
+	printf( "My IP address is " );
+	print_ip( MyIPaddr );
+	printf( "\n" );
+
+	strcpy( image_name, reply->bootp.file );
+	return( 0 );
+}
+
+
+/* --------------------------------------------------------------------- */
+/*								TFTP Procedure							 */
+
+
+static int tftp( char *image_name )
+
+{	TFTP	spkt;
+	Packet	_rpkt;
+	TFTP	*rpkt = (TFTP *)&_rpkt;
+	unsigned short	mytid, rtid = 0;
+	int				blk, retries, i, wpos, err, len, datalen;
+	static char		rotchar[4] = { '|', '/', '-', '\\' };
+	
+	retries = 5;
+	/* Construct and send a read request */
+  repeat_req:
+	spkt.tftp.req.opcode = TFTP_RRQ;
+	strcpy( spkt.tftp.req.name, image_name );
+	strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
+	mytid = _hz_200 & 0xffff;
+	
+	if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
+									   strlen(image_name) + 1 +
+									   strlen( "octect" ) +1,
+						 mytid, UDP_TFTP )) < 0) {
+		printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
+		if (--retries > 0)
+			goto repeat_req;
+		return( -1 );
+	}
+
+	retries = 5;
+	for( i = 0; i < KFILE_N_CHUNKS; ++i )
+		KFile[i] = NULL;
+	wpos = 0;
+	printf( "Receiving kernel image %s:\n", image_name );
+
+	for( blk = 1; ; ++blk ) {
+
+	  repeat_data:
+		if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
+			printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
+			if (--retries > 0)
+				goto repeat_data;
+			goto err;
+		}
+		if (rtid == 0)
+			/* Store the remote port at the first packet received */
+			rtid = rpkt->udp.src_port;
+
+		if (rpkt->tftp.opcode == TFTP_ERROR) {
+			if (strlen(rpkt->tftp.error.str) > 0)
+				printf( "TFTP error: %s\n", rpkt->tftp.error.str );
+			else
+				printf( "TFTP error #%d (no description)\n",
+						rpkt->tftp.error.errcode );
+			goto err;
+		}
+		else if (rpkt->tftp.opcode != TFTP_DATA) {
+			printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
+			if (--retries > 0)
+				goto repeat_data;
+			goto err;
+		}
+
+		if (rpkt->tftp.data.nr != blk) {
+			/* doubled data packet; ignore it */
+			goto repeat_data;
+		}
+		datalen = len - sizeof(rpkt->tftp.data.opcode) -
+			            sizeof(rpkt->tftp.data.nr);
+		
+		/* store data */
+		if (datalen > 0) {
+			int chunk = wpos >> KFILE_CHUNK_BITS;
+			if (chunk >= KFILE_N_CHUNKS) {
+				printf( "TFTP: file too large! Aborting.\n" );
+			  out_of_mem:
+				spkt.tftp.error.opcode = TFTP_ERROR;
+				spkt.tftp.error.errcode = 3;
+				strcpy( spkt.tftp.error.str, "Out of memory" );
+				udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
+				goto err;
+			}
+			if (!KFile[chunk]) {
+				if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
+					printf( "TFTP: Out of memory for kernel image\n" );
+					goto out_of_mem;
+				}
+			}
+			memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
+					rpkt->tftp.data.data, datalen );
+			wpos += datalen;
+
+#define	DISPLAY_BITS 13
+			if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
+				printf( "\r %c %7d Bytes ",
+						rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
+				fflush( stdout );
+			}
+		}
+
+		/* Send ACK packet */
+	  repeat_ack:
+		spkt.tftp.ack.opcode = TFTP_ACK;
+		spkt.tftp.ack.nr = blk;
+		if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
+							 mytid, rtid )) < 0) {
+			printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
+			if (--retries > 0)
+				goto repeat_ack;
+			goto err;
+		}
+
+		if (datalen < 512) {
+			/* This was the last packet */
+			printf( "\r   %7d Bytes done\n\n", wpos );
+			break;
+		}
+
+		retries = 5;
+	}
+
+	KFileSize = wpos;
+	return( 0 );
+
+  err:
+	free_kfile();
+	return( -1 );
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/*				  UDP/IP Protocol Quick Hack Implementation				 */
+
+
+static int udp_send( UDP *pkt, int len, int fromport, int toport )
+
+{
+	/* UDP layer */
+	pkt->udp.src_port = fromport;
+	pkt->udp.dst_port = toport;
+	pkt->udp.len      = (len += sizeof(struct udphdr));
+	pkt->udp.chksum   = 0; /* Too lazy to calculate :-) */
+
+	/* IP layer */
+	pkt->ip.version  = 4;
+	pkt->ip.ihl      = 5;
+	pkt->ip.tos      = 0;
+	pkt->ip.tot_len  = (len += sizeof(struct iphdr));
+	pkt->ip.id       = 0;
+	pkt->ip.frag_off = 0;
+	pkt->ip.ttl      = 255;
+	pkt->ip.protocol = 17; /* UDP */
+	pkt->ip.src_addr = MyIPaddr;
+	pkt->ip.dst_addr = ServerIPaddr;
+	pkt->ip.chksum   = 0;
+	pkt->ip.chksum   = ip_checksum( &pkt->ip );
+
+	/* Ethernet layer */
+	memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
+	memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
+	pkt->ether.type     = 0x0800;
+	len += sizeof(struct etherhdr);
+
+	return( eth_send( (Packet *)pkt, len ) );
+}
+
+
+static unsigned short ip_checksum( struct iphdr *buf )
+
+{	unsigned long sum = 0, wlen = 5;
+
+	__asm__ ("subqw #1,%2\n"
+			 "1:\t"
+			 "movel %1@+,%/d0\n\t"
+			 "addxl %/d0,%0\n\t"
+			 "dbra %2,1b\n\t"
+			 "movel %0,%/d0\n\t"
+			 "swap %/d0\n\t"
+			 "addxw %/d0,%0\n\t"
+			 "clrw %/d0\n\t"
+			 "addxw %/d0,%0"
+			 : "=d" (sum), "=a" (buf), "=d" (wlen)
+			 : "0" (sum), "1" (buf), "2" (wlen)
+			 : "d0");
+	return( (~sum) & 0xffff );
+}
+
+
+static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
+
+{	int				err;
+
+  repeat:
+	if ((err = eth_rcv( (Packet *)pkt, len )))
+		return( err );
+	
+	/* Ethernet layer */
+	if (pkt->ether.type == 0x0806) {
+		/* ARP */
+		ARP *pk = (ARP *)pkt;
+		unsigned char *shw, *sip, *thw, *tip;
+
+		if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
+			pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
+			/* Wrong hardware type or protocol; or reply -> ignore */
+			goto repeat;
+		shw = pk->arp.addr;
+		sip = shw + pk->arp.hln;
+		thw = sip + pk->arp.pln;
+		tip = thw + pk->arp.hln;
+		
+		if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
+			memcpy( thw, shw, pk->arp.hln );
+			memcpy( tip, sip, pk->arp.pln );
+			memcpy( shw, &MyHwaddr, pk->arp.hln );
+			memcpy( sip, &MyIPaddr, pk->arp.pln );
+
+			memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
+			memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
+			eth_send( (Packet *)pk, *len );
+		}
+		goto repeat;
+	}
+	else if (pkt->ether.type != 0x0800) {
+		printf( "Unknown Ethernet packet type %04x received\n",
+				pkt->ether.type );
+		goto repeat;
+	}
+
+	/* IP layer */
+	if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
+		printf( "Received packet for wrong IP address\n" );
+		goto repeat;
+	}
+	if (ServerIPaddr != IP_Unknown_Addr &&
+		ServerIPaddr != IP_Broadcast_Addr &&
+		pkt->ip.src_addr != ServerIPaddr) {
+		printf( "Received packet from wrong server\n" );
+		goto repeat;
+	}
+	/* If IP header is longer than 5 longs, delete the options */
+	if (pkt->ip.ihl > 5) {
+		char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
+		memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
+	}
+	
+	/* UDP layer */
+	if (fromport != 0 && pkt->udp.src_port != fromport) {
+		printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
+		goto repeat;
+	}
+	if (pkt->udp.dst_port != atport) {
+		printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
+		goto repeat;
+	}
+
+	*len = pkt->udp.len - sizeof(struct udphdr);
+	return( 0 );
+}
+
+
+/* --------------------------------------------------------------------- */
+/*							   Address Printing							 */
+
+
+static void print_ip( IPADDR addr )
+
+{
+	printf( "%ld.%ld.%ld.%ld",
+			(addr >> 24) & 0xff,
+			(addr >> 16) & 0xff,
+			(addr >>  8) & 0xff,
+			addr & 0xff );
+}
+
+
+static void print_hw( HWADDR addr )
+
+{
+	printf( "%02x:%02x:%02x:%02x:%02x:%02x",
+			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
+}
+
+
+/* --------------------------------------------------------------------- */
+/*					 Ethernet Interface Abstraction Layer				 */
+
+
+#ifdef ETHLL_LANCE
+#include "ethlance.h"
+#endif
+
+static ETHIF_SWITCH *PossibleInterfaces[] = {
+#ifdef ETHLL_LANCE
+	&LanceSwitch,
+#endif
+};
+
+#define	N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
+
+/* Detected interface */
+static ETHIF_SWITCH *Ethif = NULL;
+
+
+static int check_ethif( void )
+
+{	int i;
+
+	/* Check for configured interfaces */
+	Ethif = NULL;
+	for( i = 0; i < N_PossibleInterfaces; ++i ) {
+		if (PossibleInterfaces[i]->probe() >= 0) {
+			Ethif = PossibleInterfaces[i];
+			break;
+		}
+	}
+	if (!Ethif)
+		return( -1 );
+
+	if (Ethif->init() < 0) {
+		printf( "Ethernet interface initialization failed\n" );
+		return( -1 );
+	}
+	Ethif->get_hwaddr( &MyHwaddr );
+	return( 0 );
+}
+
+
+static int eth_send( Packet *pkt, int len )
+
+{
+	return( Ethif->snd( pkt, len ));
+}
+
+
+static int eth_rcv( Packet *pkt, int *len )
+
+{
+	return( Ethif->rcv( pkt, len ));
+}
+
+
+#if 0
+static void dump_packet( UDP *pkt )
+
+{	int		i, l;
+	unsigned char *p;
+	
+	printf( "Packet dump:\n" );
+
+	printf( "Ethernet header:\n" );
+	printf( "  dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
+	printf( "  src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
+	printf( "  type: %04x\n", pkt->ether.type );
+
+	printf( "IP header:\n" );
+	printf( "  version: %d\n", pkt->ip.version );
+	printf( "  hdr len: %d\n", pkt->ip.ihl );
+	printf( "  tos: %d\n", pkt->ip.tos );
+	printf( "  tot_len: %d\n", pkt->ip.tot_len );
+	printf( "  id: %d\n", pkt->ip.id );
+	printf( "  frag_off: %d\n", pkt->ip.frag_off );
+	printf( "  ttl: %d\n", pkt->ip.ttl );
+	printf( "  prot: %d\n", pkt->ip.protocol );
+	printf( "  src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
+	printf( "  dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
+
+	printf( "UDP header:\n" );
+	printf( "  src port: %d\n", pkt->udp.src_port );
+	printf( "  dst port: %d\n", pkt->udp.dst_port );
+	printf( "  len: %d\n", pkt->udp.len );
+
+	printf( "Data:" );
+	l = pkt->udp.len - sizeof(pkt->udp);
+	p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
+	for( i = 0; i < l; ++i ) {
+		if ((i % 32) == 0)
+			printf( "\n  %04x ", i );
+		printf( "%02x ", *p );
+	}
+	printf( "\n" );
+}
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootp.h linux/arch/m68k/boot/atari/bootp.h
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootp.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/bootp.h	Wed Sep 25 10:47:39 1996
@@ -0,0 +1,44 @@
+#ifndef _bootp_h
+#define _bootp_h
+
+/* --------------------------------------------------------------------- */
+/*							 Ethernet Definitions						 */
+
+#define	PKTLEN			1544
+typedef unsigned char	Packet[PKTLEN];
+
+#define	ETHADDRLEN		6
+typedef unsigned char	HWADDR[ETHADDRLEN];
+
+typedef struct {
+	int		(*probe)( void );
+	int		(*init)( void );
+	void	(*get_hwaddr)( HWADDR *addr );
+	int		(*snd)( Packet *pkt, int len );
+	int		(*rcv)( Packet *pkt, int *len );
+} ETHIF_SWITCH;
+
+
+/* error codes */
+#define	ETIMEO	-1		/* Timeout */
+#define	ESEND	-2		/* General send error (carrier, abort, ...) */
+#define	ERCV	-3		/* General receive error */
+#define	EFRAM	-4		/* Framing error */
+#define	EOVERFL	-5		/* Overflow (too long packet) */
+#define	ECRC	-6		/* CRC error */
+
+
+typedef unsigned long IPADDR;
+
+
+/***************************** Prototypes *****************************/
+
+int get_remote_kernel( const char *kname );
+int kread( int fd, void *buf, unsigned cnt );
+int klseek( int fd, int where, int whence );
+int kclose( int fd );
+
+/************************* End of Prototypes **************************/
+
+#endif  /* _bootp_h */
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/bootstrap.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/boot/atari/bootstrap.c	Wed Sep 25 10:47:39 1996
@@ -43,7 +43,7 @@
 #include <asm/page.h>
 
 #define _LINUX_TYPES_H		/* Hack to prevent including <linux/types.h> */
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 
 /* Atari bootstrap include file */
 #include "bootstrap.h"
@@ -162,6 +162,33 @@
 }
 
 
+/* Test if FPU instructions are executed in hardware, or if they're
+   emulated in software.  For this, the F-line vector is temporarily
+   replaced. */
+
+int test_software_fpu(void)
+{
+	int rv = 0;
+
+	__asm__ __volatile__
+		( "movel	0x2c,a0\n\t"
+		  "movel	sp,a1\n\t"
+		  "movel	#Lfline,0x2c\n\t"
+		  "moveq	#1,%0\n\t"
+		  "fnop 	\n\t"
+		  "nop		\n\t"
+		  "moveq	#0,%0\n"
+		"Lfline:\t"
+		  "movel	a1,sp\n\t"
+		  "movel	a0,0x2c"
+		  : "=d" (rv)
+		  : /* no inputs */
+		  : "a0", "a1" );
+
+	return rv;
+}
+
+
 void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
 
 {	static u_long	save_addr;
@@ -248,6 +275,47 @@
 #undef TESTADDR
 #undef TESTPAT
 
+
+static int check_bootinfo_version(char *memptr)
+{
+    struct bootversion *bv = (struct bootversion *)memptr;
+    unsigned long version = 0;
+    int i, kernel_major, kernel_minor, boots_major, boots_minor;
+
+    printf( "\n" );
+    if (bv->magic == BOOTINFOV_MAGIC) {
+	for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
+	    if (bv->machversions[i].machtype == MACH_ATARI) {
+		version = bv->machversions[i].version;
+		break;
+	    }
+	}
+    }
+    if (!version)
+	printf("Kernel has no bootinfo version info, assuming 0.0\n");
+
+    kernel_major = BI_VERSION_MAJOR(version);
+    kernel_minor = BI_VERSION_MINOR(version);
+    boots_major  = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
+    boots_minor  = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
+    printf("Bootstrap's bootinfo version: %d.%d\n",
+	   boots_major, boots_minor);
+    printf("Kernel's bootinfo version   : %d.%d\n",
+	   kernel_major, kernel_minor);
+    
+    if (kernel_major != boots_major) {
+	printf("\nThis bootstrap is too %s for this kernel!\n",
+	       boots_major < kernel_major ? "old" : "new");
+	return 0;
+    }
+    if (kernel_minor > boots_minor) {
+	printf("Warning: Bootinfo version of bootstrap and kernel differ!\n");
+	printf("         Certain features may not work.\n");
+    }
+    return 1;
+}
+
+
 #ifdef USE_BOOTP
 # include "bootp.h"
 #else
@@ -287,7 +355,7 @@
     kernel_name = "vmlinux";
 
     /* print the startup message */
-    puts("\fLinux/68k Atari Bootstrap version 1.6"
+    puts("\fLinux/68k Atari Bootstrap version 1.8"
 #ifdef USE_BOOTP
 	 " (with BOOTP)"
 #endif
@@ -329,7 +397,7 @@
 	    break;
 #ifdef USE_BOOTP
 	  case 'b':
-	    prefer_bootp = 1;
+	    prefer_bootp = 0;
 	    break;
 #endif
 	  case '?':
@@ -370,8 +438,7 @@
     getcookie("_MCH", &mch_type);
 
     /* check if we are on a 68030/40 with FPU */
-    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60) ||
-		(fpu_type >> 16) < 2)
+    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
     {
 	puts("Machine type currently not supported. Aborting...");
 	boot_exit(EXIT_FAILURE);
@@ -404,10 +471,13 @@
 		puts( "68060\n" );
 	}
 	else {
-		switch ((fpu_type >> 16) & 6) {
+		switch ((fpu_type >> 16) & 7) {
 		  case 0:
 			puts("not present\n");
 			break;
+		  case 1:
+			puts("SFP004 not supported. Assuming no FPU.");
+			break;
 		  case 2:
 			/* try to determine real type */
 			if (fpu_idle_frame_size () != 0x18)
@@ -427,6 +497,14 @@
 			break;
 		}
 	}
+	/* ++roman: If an FPU was announced in the cookie, test
+	   whether it is a real hardware FPU or a software emulator!  */
+	if (bi.cputype & FPU_MASK) {
+		if (test_software_fpu()) {
+			bi.cputype &= ~FPU_MASK;
+			puts("FPU: software emulated. Assuming no FPU.");
+		}
+	}
 
     memset(&bi.bi_atari.hw_present, 0, sizeof(bi.bi_atari.hw_present));
 
@@ -766,7 +844,9 @@
       }
     else
       kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
-    memreq = kernel_size + sizeof (bi) + rd_size;
+    memreq = kernel_size + sizeof (bi);
+    /* align load address of ramdisk image, read() is sloooow on odd addr. */
+    memreq = ((memreq + 3) & ~3) + rd_size;
 	
     /* allocate RAM for the kernel */
     if (!(memptr = (char *)Malloc (memreq)))
@@ -824,6 +904,12 @@
       }
     kclose (kfd);
 
+    /* Check kernel's bootinfo version */
+    if (!check_bootinfo_version(memptr)) {
+	Mfree ((void *)memptr);
+	boot_exit (EXIT_FAILURE);
+    }
+    
     /* copy the boot_info struct to the end of the kernel image */
     memcpy ((void *)(memptr + kernel_size),
 	    &bi, sizeof(bi));
@@ -837,7 +923,7 @@
 	    Mfree ((void *)memptr);
 	    boot_exit (EXIT_FAILURE);
 	}
-	if (read (rfd, memptr + kernel_size + sizeof (bi),
+	if (read (rfd, memptr + memreq - rd_size,
 		  rd_size) != rd_size)
 	{
 	    fprintf (stderr, "Failed to read ramdisk file\n");
@@ -852,7 +938,7 @@
     {
 	if (bi.ramdisk_size)
 	    printf ("RAM disk at %#lx, size is %ldK\n",
-		    (u_long)memptr + kernel_size,
+		    (u_long)(memptr + memreq - rd_size),
 		    bi.ramdisk_size);
 
 	if (elf_kernel)
@@ -879,10 +965,8 @@
 		elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
 	printf ("ramdisk dest top is %#lx\n", bi.ramdisk_addr + rd_size);
 	printf ("ramdisk lower limit is %#lx\n",
-		(u_long)(memptr + kernel_size));
-	printf ("ramdisk src top is %#lx\n",
-		(u_long)(memptr + kernel_size) +
-		rd_size);
+		(u_long)(memptr + memreq - rd_size));
+	printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
 
 	printf ("Type a key to continue the Linux boot...");
 	fflush (stdout);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/ethlance.c linux/arch/m68k/boot/atari/ethlance.c
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/ethlance.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/ethlance.c	Wed Sep 25 10:47:39 1996
@@ -0,0 +1,435 @@
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bootp.h"
+#include "ethlance.h"
+
+
+struct {
+	volatile unsigned short	*memaddr;
+	volatile unsigned short	*ioaddr;
+} lance_addr_list[] = {
+	{ (void *)0xfe010000, (void *)0xfe00fff0 },	/* RieblCard VME in TT */
+	{ (void *)0xfec10000, (void *)0xfec0fff0 },	/* RieblCard VME in MegaSTE
+												   (highest byte stripped) */
+	{ (void *)0xfee00000, (void *)0xfeff7000 },	/* RieblCard in ST
+												   (highest byte stripped) */
+	{ (void *)0xfecf0000, (void *)0xfecffff0 },	/* PAMCard VME in TT and MSTE
+												   (highest byte stripped) */
+};
+
+#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+
+#define TX_RING_SIZE			1
+#define TX_RING_LEN_BITS		0
+
+#define RX_RING_SIZE			16
+#define RX_RING_LEN_BITS		(4 << 5)
+
+#define	offsetof(type,elt)	((unsigned long)(&(((type *)0)->elt)))
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+	unsigned short			base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+	short					buf_length;	/* This length is 2s complement! */
+	short					msg_length;	/* This length is "normal". */
+};
+
+struct lance_tx_head {
+	unsigned short			base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+	short					length;		/* Length is 2s complement! */
+	volatile short			misc;
+};
+
+struct ringdesc {
+	unsigned short	adr_lo;		/* Low 16 bits of address */
+	unsigned char	len;		/* Length bits */
+	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
+};
+
+struct lance_packet {
+	volatile unsigned char	data[PKTLEN];
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+	unsigned short	mode;		/* Pre-set mode */
+	unsigned char	hwaddr[6];	/* Physical ethernet address */
+	unsigned		filter[2];	/* Multicast filter (unused). */
+	/* Receive and transmit ring base, along with length bits. */
+	struct ringdesc	rx_ring;
+	struct ringdesc	tx_ring;
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+	struct lance_init_block	init;
+	struct lance_tx_head	tx_head[TX_RING_SIZE];
+	struct lance_rx_head	rx_head[RX_RING_SIZE];
+	struct lance_packet		tx_packet[TX_RING_SIZE];
+	struct lance_packet		rx_packet[TX_RING_SIZE];
+};
+
+#define RIEBL_MAGIC			0x09051990
+#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
+#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
+#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
+
+struct lance_ioreg {
+/* base+0x0 */	volatile unsigned short	data;
+/* base+0x2 */	volatile unsigned short	addr;
+				unsigned char			_dummy1[3];
+/* base+0x7 */	volatile unsigned char	ivec;
+				unsigned char			_dummy2[5];
+/* base+0xd */	volatile unsigned char	eeprom;
+				unsigned char			_dummy3;
+/* base+0xf */	volatile unsigned char	mem;
+};
+
+enum lance_type {
+	OLD_RIEBL,		/* old Riebl card without battery */
+	NEW_RIEBL,		/* new Riebl card with battery */
+	PAM_CARD		/* PAM card with EEPROM */
+} CardType;
+
+HWADDR	dev_addr;
+
+/* This is a default address for the old RieblCards without a battery
+ * that have no ethernet address at boot time. 00:00:36:04 is the
+ * prefix for Riebl cards, the 00:00 at the end is arbitrary.
+ */
+
+HWADDR OldRieblDefHwaddr = {
+	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
+};
+
+struct lance_ioreg	*IO;
+struct lance_memory	*MEM;
+
+#define	DREG	IO->data
+#define	AREG	IO->addr
+#define	REGA(a)	( AREG = (a), DREG )
+
+int CurRx;
+
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define	TMD1_ENP		0x01
+#define TMD1_STP		0x02
+#define	TMD1_DEF		0x04
+#define TMD1_ONE		0x08
+#define	TMD1_MORE		0x10
+#define	TMD1_ERR		0x40
+#define TMD1_OWN 		0x80
+
+#define TMD1_OWN_CHIP	TMD1_OWN
+#define TMD1_OWN_HOST	0
+
+/* tx_head misc field */
+#define TMD3_TDR		0x03FF
+#define TMD3_RTRY		0x0400
+#define TMD3_LCAR		0x0800
+#define TMD3_LCOL		0x1000
+#define TMD3_UFLO		0x4000
+#define TMD3_BUFF3		0x8000
+
+/* rx_head flags */
+#define	RMD1_ENP		0x01
+#define RMD1_STP		0x02
+#define RMD1_BUFF		0x04
+#define RMD1_CRC		0x08
+#define RMD1_OFLO		0x10
+#define RMD1_FRAM		0x20
+#define	RMD1_ERR		0x40
+#define RMD1_OWN 		0x80
+
+#define RMD1_OWN_CHIP	RMD1_OWN
+#define RMD1_OWN_HOST	0
+
+/* register names */
+#define CSR0	0
+#define CSR1	1
+#define CSR2	2
+#define CSR3	3
+
+/* CSR0 */
+#define CSR0_INIT	0x0001		/* initialize */
+#define CSR0_STRT	0x0002		/* start */
+#define CSR0_STOP	0x0004		/* stop */
+#define CSR0_TDMD	0x0008		/* transmit demand */
+#define CSR0_TXON	0x0010		/* transmitter on */
+#define CSR0_RXON	0x0020		/* receiver on */
+#define CSR0_INEA	0x0040		/* interrupt enable */
+#define CSR0_INTR	0x0080		/* interrupt active */
+#define CSR0_IDON	0x0100		/* initialization done */
+#define CSR0_TINT	0x0200		/* transmitter interrupt */
+#define CSR0_RINT	0x0400		/* receiver interrupt */
+#define CSR0_MERR	0x0800		/* memory error */
+#define CSR0_MISS	0x1000		/* missed frame */
+#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) */
+#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits */
+#define CSR0_ERR	0x8000		/* error */
+
+/* CSR3 */
+#define CSR3_BCON	0x0001
+#define CSR3_ACON	0x0002
+#define CSR3_BSWP	0x0004
+
+
+#define	HZ	200
+#define	_hz_200	(*(volatile unsigned long *)0x4ba)
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static int lance_probe( void );
+static int addr_readable( volatile void *regp, int wordflag );
+static int lance_init( void );
+static void lance_get_hwaddr( HWADDR *addr );
+static int lance_snd( Packet *pkt, int len );
+static int lance_rcv( Packet *pkt, int *len );
+
+/************************* End of Prototypes **************************/
+
+
+
+ETHIF_SWITCH LanceSwitch = {
+	lance_probe, lance_init, lance_get_hwaddr, 
+	lance_snd, lance_rcv
+};
+
+
+static int lance_probe( void )
+
+{	int		i;
+	
+	for( i = 0; i < N_LANCE_ADDR; ++i ) {
+		if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
+			(lance_addr_list[i].memaddr[0] = 1,
+			 lance_addr_list[i].memaddr[0] == 1) &&
+			(lance_addr_list[i].memaddr[0] = 0,
+			 lance_addr_list[i].memaddr[0] == 0) &&
+			addr_readable( lance_addr_list[i].ioaddr, 1 )) {
+			break;
+		}
+	}
+	if (i == N_LANCE_ADDR) return( -1 );
+
+	IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
+	MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
+	REGA( CSR0 ) = CSR0_STOP;
+
+	return( 0 );
+}
+
+
+static int addr_readable( volatile void *regp, int wordflag )
+
+{	int		ret;
+	long	*vbr, save_berr;
+
+	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=r" (vbr) : );
+	save_berr = vbr[2];
+	
+	__asm__ __volatile__
+	(	"movel	%/sp,%/d1\n\t"
+		"movel	#Lberr,%2@\n\t"
+		"moveq	#0,%0\n\t"
+		"tstl   %3\n\t"
+		"bne	1f\n\t"
+		"tstb	%1@\n\t"
+		"bra	2f\n"
+"1:		 tstw	%1@\n"
+"2:		 moveq	#1,%0\n"
+"Lberr:	 movel	%/d1,%/sp"
+		: "=&d" (ret)
+		: "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
+		: "d1", "memory"
+	);
+
+	vbr[2] = save_berr;
+	
+	return( ret );
+}
+
+
+static int lance_init( void )
+
+{	int		i;
+	
+	/* Now test for type: If the eeprom I/O port is readable, it is a
+	 * PAM card */
+	if (addr_readable( &(IO->eeprom), 0 )) {
+		/* Switch back to Ram */
+		i = IO->mem;
+		CardType = PAM_CARD;
+	}
+	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
+		CardType = NEW_RIEBL;
+	}
+	else
+		CardType = OLD_RIEBL;
+		
+	/* Get the ethernet address */
+	switch( CardType ) {
+	  case OLD_RIEBL:
+		/* No ethernet address! (Set some default address) */
+		memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
+		break;
+	  case NEW_RIEBL:
+		memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
+		break;
+	  case PAM_CARD:
+		i = IO->eeprom;
+		for( i = 0; i < ETHADDRLEN; ++i )
+			dev_addr[i] = 
+				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
+				((((unsigned short *)MEM)[i*2+1] & 0x0f));
+		i = IO->mem;
+		break;
+	}
+
+	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
+	for( i = 0; i < ETHADDRLEN; i++ )
+		MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
+	MEM->init.filter[0] = 0x00000000;
+	MEM->init.filter[1] = 0x00000000;
+	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
+	MEM->init.rx_ring.adr_hi = 0;
+	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
+	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
+	MEM->init.tx_ring.adr_hi = 0;
+	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
+	
+	REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0); 
+	REGA( CSR2 ) = 0;
+	REGA( CSR1 ) = 0;
+	REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
+
+	i = 1000000;
+	while( i-- > 0 )
+		if (DREG & CSR0_IDON)
+			break;
+	if (i < 0 || (DREG & CSR0_ERR)) {
+		DREG = CSR0_STOP;
+		return( -1 );
+	}
+	DREG = CSR0_IDON;
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
+		MEM->tx_head[i].flag = TMD1_OWN_HOST;
+ 		MEM->tx_head[i].base_hi = 0;
+		MEM->tx_head[i].length = 0;
+		MEM->tx_head[i].misc = 0;
+	}
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
+		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+		MEM->rx_head[i].base_hi = 0;
+		MEM->rx_head[i].buf_length = -PKTLEN;
+		MEM->rx_head[i].msg_length = 0;
+	}
+	CurRx = 0;
+	
+	return( 0 );
+}
+
+
+static void lance_get_hwaddr( HWADDR *addr )
+
+{
+	memcpy( addr, dev_addr, ETHADDRLEN );
+}
+
+
+static int lance_snd( Packet *pkt, int len )
+
+{	unsigned long timeout;
+	
+	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
+	len = (len < 60) ? 60 : len;
+	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
+	if (CardType == PAM_CARD && (len & 1))
+		++len;
+
+	MEM->tx_head[0].length = -len;
+	MEM->tx_head[0].misc = 0;
+	memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
+	MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
+	MEM->tx_head[0].base_hi = 0;
+	MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+
+	/* Trigger an immediate send poll. */
+	REGA( CSR0 ) = CSR0_TDMD;
+
+	/* Wait for packet being sent */
+	timeout = _hz_200 + 3*HZ;
+	while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
+		   !MEM->tx_head[0].misc &&
+		   _hz_200 < timeout )
+		;
+
+	if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
+		!(MEM->tx_head[0].misc & TMD1_ERR))
+		/* sent ok */
+		return( 0 );
+
+	/* failure */
+	if (_hz_200 >= timeout)
+		return( ETIMEO );
+	if (MEM->tx_head[0].misc & TMD3_UFLO) {
+		/* On FIFO errors, must re-turn on TX! */
+		DREG = CSR0_STRT;
+	}
+
+	return( ESEND );
+}
+
+
+static int lance_rcv( Packet *pkt, int *len )
+
+{	unsigned long	timeout;
+	int				stat;
+	
+	/* Wait for a packet */
+	timeout = _hz_200 + 4*HZ;
+	while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
+		   _hz_200 < timeout )
+		;
+	/* Not ours -> was a timeout */
+	if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
+		return( ETIMEO );
+
+	/* Check for errors */
+	if (stat != (RMD1_ENP|RMD1_STP)) {
+		MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
+		if (stat & RMD1_FRAM) return( EFRAM );
+		if (stat & RMD1_OFLO) return( EOVERFL );
+		if (stat & RMD1_CRC)  return( ECRC );
+		return( ERCV );
+	}
+
+	/* Get the packet */
+	*len = MEM->rx_head[CurRx].msg_length & 0xfff;
+	memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
+
+	/* Give the buffer back to the chip */
+	MEM->rx_head[CurRx].buf_length = -PKTLEN;
+	MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
+	CurRx = (CurRx + 1) % RX_RING_SIZE;
+
+	return( 0 );
+}
+
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/atari/ethlance.h linux/arch/m68k/boot/atari/ethlance.h
--- lx2.0/v2.0.21/linux/arch/m68k/boot/atari/ethlance.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/ethlance.h	Wed Sep 25 10:47:39 1996
@@ -0,0 +1,7 @@
+
+#ifndef _ethlance_h
+#define _ethlance_h
+
+extern ETHIF_SWITCH LanceSwitch;
+
+#endif /* _ethlance_h */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- lx2.0/v2.0.21/linux/arch/m68k/config.in	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/config.in	Wed Sep 25 10:47:39 1996
@@ -5,6 +5,11 @@
 mainmenu_name "Linux/68k Kernel Configuration"
 
 mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
@@ -14,22 +19,48 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'General setup'
+comment 'Platform dependant setup'
 
 bool 'Amiga support' CONFIG_AMIGA
 bool 'Atari support' CONFIG_ATARI
 bool 'Macintosh support' CONFIG_MAC
-bool '68040 floating point software package' CONFIG_FPSP_040
-bool '68060 integer/floating point software package' CONFIG_IFPSP_060
+
+comment 'Processor type'
+bool '68020 support' CONFIG_M68020
+bool '68030 support' CONFIG_M68030
+bool '68040 support' CONFIG_M68040
+if [ "$CONFIG_M68040" = "y" ]; then
+  bool 'Use 68040 specific optimizations' CONFIG_OPTIMIZE_040
+fi
+bool '68060 support' CONFIG_M68060
+if [ "$CONFIG_M68060" = "y" ]; then
+  bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060
+fi
+bool 'Advanced processor options' CONFIG_ADVANCED_CPU
+if [ "$CONFIG_ADVANCED_CPU" = "y" ]; then
+  bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
-  bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
+bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
+  bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS
+  bool 'Amiga ECS chipset support' CONFIG_AMIFB_ECS
+  bool 'Amiga AGA chipset support' CONFIG_AMIFB_AGA
+  bool 'Amiga Cybervision support' CONFIG_FB_CYBER
+  bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP
+  if [ "$CONFIG_AMIGA_GSP" = "y" ]; then
+    bool 'DMI Resolver support' CONFIG_GSP_RESOLVER
+#    bool 'A2410 support' CONFIG_GSP_A2410
+  fi
 fi
 endmenu
 
@@ -41,20 +72,33 @@
 
 tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
 bool 'IDE harddisk support' CONFIG_BLK_DEV_IDE
+if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+  bool '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD
+fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
-bool 'Amiga Cybervision support' CONFIG_FB_CYBER
-bool 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
 bool 'Atari ACSI support' CONFIG_ATARI_ACSI
+if [ "$CONFIG_ATARI_ACSI" = "y" ]; then
+comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
+bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
+bool 'Atari SLM laser printer support' CONFIG_ATARI_SLM
+fi
 fi
 
+comment 'Additional Block Devices'
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
+if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
+  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
+fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
   bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
 fi
-
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
@@ -68,11 +112,11 @@
 
 if [ "$CONFIG_SCSI" != "n" ]; then
 
-comment 'SCSI support type (disk, tape, CDrom)'
+comment 'SCSI support type (disk, tape, CD-ROM)'
 
 dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
 dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
 dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
 
 comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
@@ -88,9 +132,11 @@
 bool 'A3000 WD33C93A support' CONFIG_A3000_SCSI
 bool 'A2091 WD33C93A support' CONFIG_A2091_SCSI
 bool 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI
+bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
 dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
+bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
 fi
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 endmenu
@@ -112,6 +158,8 @@
 tristate 'SLIP (serial line) support' CONFIG_SLIP
 if [ "$CONFIG_SLIP" != "n" ]; then
   bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+  bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 fi
 tristate 'PPP (point-to-point) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
@@ -125,6 +173,10 @@
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   bool 'Atari Lance support' CONFIG_ATARILANCE
+if [ "$CONFIG_ATARI_ACSI" = "y" ]; then
+  bool 'BioNet-100 support' CONFIG_ATARI_BIONET
+  bool 'PAMsNet support' CONFIG_ATARI_PAMSNET
+fi
 fi
 fi
 endmenu
@@ -143,12 +195,12 @@
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
 fi
-if [ "$CONFIG_ATARI" = y ]; then
+if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
   tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
   tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
 fi
-if [ "$CONFIG_AMIGA" = y ]; then
+if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
   bool 'GVP IO-Extender support' CONFIG_GVPIOEXT
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/console/Makefile linux/arch/m68k/console/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/console/Makefile	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/console/Makefile	Wed Sep 25 10:47:39 1996
@@ -6,10 +6,19 @@
 # unless it's something special (ie not a .c file).
 #
 
-EXTRA_CFLAGS := -Wa,-m68030
+GSPA = gspa
+GSPH2C = gspahextoc
 
 L_TARGET = console.a
 L_OBJS = fbcon.o fonts.o font_8x16.o font_8x8.o pearl_8x8.o
 M_OBJS =
 
+ifdef CONFIG_AMIGA_GSP
+L_OBJS := $(L_OBJS) gspcon.o gspcore.o
+endif
+
 include $(TOPDIR)/Rules.make
+
+gspcore.c: gspcore.gsp
+	$(GSPA) $< > $*.hex
+	$(GSPH2C) $*.hex > gspcore.c
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c
--- lx2.0/v2.0.21/linux/arch/m68k/console/fbcon.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/console/fbcon.c	Wed Sep 25 10:47:39 1996
@@ -40,6 +40,7 @@
 
 
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
@@ -49,7 +50,7 @@
 #include <linux/kd.h>
 #include <linux/malloc.h>
 
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/irq.h>
 #ifdef CONFIG_AMIGA
 #include <asm/amigahw.h>
@@ -269,7 +270,7 @@
 static __inline__ u_long expand2l(u_char c);
 static __inline__ u_short dup2w(u_char c);
 static __inline__ int real_y(struct display *p, int y);
-static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy);
+static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
                             int height, int width, u_int y_break);
 
@@ -520,19 +521,19 @@
 #ifdef CONFIG_AMIGA
    if (MACH_IS_AMIGA) {
       cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE;
-      irqres = add_isr(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, NULL,
-                       "console/cursor");
+      irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0,
+                           "console/cursor", fbcon_vbl_handler);
    }
 #endif /* CONFIG_AMIGA */
 #ifdef CONFIG_ATARI
    if (MACH_IS_ATARI) {
       cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
-      irqres = add_isr(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, NULL,
-		       "console/cursor");
+      irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO,
+                           "console/cursor", fbcon_vbl_handler);
    }
 #endif /* CONFIG_ATARI */
 
-   if (!irqres)
+   if (irqres)
       panic("fbcon_startup: Couldn't add vblank interrupt");
 
    return(kmem_start);
@@ -1487,7 +1488,7 @@
 }
 
 
-static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy)
+static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
 {
    struct display *p;
 
@@ -1713,7 +1714,7 @@
 {
 	int unit = conp->vc_num;
 	struct display *p = &disp[unit];
-	int i, size, alloc;
+	int i, j, size, alloc;
 
 	size = (p->fontwidth+7)/8 * p->fontheight * 256;
 	alloc = (*w+7)/8 * *h * 256;
@@ -1724,10 +1725,9 @@
 		/* allocation length not sufficient */
 		return( -ENAMETOOLONG );
 
-	if ((i = verify_area( VERIFY_WRITE, (void *)data, size )))
-		return i;
-
-	memcpy_tofs( data, p->fontdata, size );
+	for (i = 0; i < 256; i++)
+		for (j = 0; j < p->fontheight; j++)
+			data[i*32+j] = p->fontdata[i*p->fontheight+j];
 	return( 0 );
 }
 
@@ -1738,7 +1738,7 @@
 {
 	int unit = conp->vc_num;
 	struct display *p = &disp[unit];
-	int i, size, userspace = 1, resize;
+	int i, j, size, userspace = 1, resize;
 	char *old_data = NULL, *new_data;
 
 	if (w < 0)
@@ -1794,13 +1794,15 @@
 		old_data = p->fontdata;
 	
 	if (userspace) {
-		if ((i = verify_area( VERIFY_READ, (void *)data, size )))
-			return i;
 		if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
 			return( -ENOMEM );
 		new_data += sizeof(int);
 		REFCOUNT(new_data) = 1; /* usage counter */
-		memcpy_fromfs( new_data, data, size );
+
+		for (i = 0; i < 256; i++)
+			for (j = 0; j < h; j++)
+				new_data[i*h+j] = data[i*32+j];
+
 		p->fontdata = new_data;
 		p->userfont = 1;
 	}
@@ -1814,6 +1816,9 @@
   activate:
 	if (resize) {
 		p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
+		/* Adjust the virtual screen-size to fontheight*rows */
+		p->var.yres_virtual = (p->var.yres/h)*h;
+		p->vrows = p->var.yres_virtual/h;
 		if (divides(p->ywrapstep, p->fontheight))
 			p->scrollmode = SCROLL_YWRAP;
 		else if (divides(p->ypanstep, p->fontheight) &&
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/console/fonts.c linux/arch/m68k/console/fonts.c
--- lx2.0/v2.0.21/linux/arch/m68k/console/fonts.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/console/fonts.c	Wed Sep 25 10:47:39 1996
@@ -12,8 +12,8 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
+#include <asm/setup.h>
 #include <asm/font.h>
-#include <asm/bootinfo.h>
 
 
    /*
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- lx2.0/v2.0.21/linux/arch/m68k/defconfig	Mon May  6 12:44:30 1996
+++ linux/arch/m68k/defconfig	Wed Sep 25 10:47:39 1996
@@ -3,6 +3,11 @@
 #
 
 #
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
 # Loadable module support
 #
 # CONFIG_MODULES is not set
@@ -10,30 +15,57 @@
 # CONFIG_KERNELD is not set
 
 #
-# General setup
+# Platform dependant setup
 #
 CONFIG_AMIGA=y
 # CONFIG_ATARI is not set
 # CONFIG_MAC is not set
-CONFIG_FPSP_040=y
-# CONFIG_IFPSP_060 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+# CONFIG_OPTIMIZE_040 is not set
+# CONFIG_M68060 is not set
+# CONFIG_OPTIMIZE_060 is not set
+# CONFIG_ADVANCED_CPU is not set
+# CONFIG_RMW_INSNS is not set
+
+#
+# General setup
+#
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_ZORRO is not set
+CONFIG_ZORRO=y
+CONFIG_AMIFB_OCS=y
+CONFIG_AMIFB_ECS=y
+CONFIG_AMIFB_AGA=y
+# CONFIG_FB_CYBER is not set
+# CONFIG_AMIGA_GSP is not set
+# CONFIG_GSP_RESOLVER is not set
+# CONFIG_GSP_A2410 is not set
 
 #
 # Block device driver configuration
 #
 CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_IDE is not set
-# CONFIG_FB_CYBER is not set
 # CONFIG_AMIGA_Z2RAM is not set
 # CONFIG_ATARI_ACSI is not set
+# CONFIG_ACSI_MULTI_LUN is not set
+# CONFIG_ATARI_SLM
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_STRIPED is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
 
 #
 # Networking options
@@ -89,6 +121,7 @@
 CONFIG_A3000_SCSI=y
 # CONFIG_A2091_SCSI is not set
 # CONFIG_GVP11_SCSI is not set
+# CONFIG_CYBERSTORM_SCSI is not set
 # CONFIG_ATARI_SCSI is not set
 
 #
@@ -102,11 +135,14 @@
 # CONFIG_A2065 is not set
 # CONFIG_HYDRA is not set
 # CONFIG_ATARILANCE is not set
+# CONFIG_ATARI_BIONET is not set
+# CONFIG_ATARI_PAMSNET is not set
 
 #
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_LOCK_MANDATORY is not set
 CONFIG_MINIX_FS=y
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
@@ -131,6 +167,11 @@
 # CONFIG_PRINTER is not set
 CONFIG_AMIGAMOUSE=y
 # CONFIG_ATARIMOUSE is not set
+CONFIG_AMIGA_BUILTIN_SERIAL=y
+# CONFIG_GVPIOEXT is not set
+# CONFIG_MULTIFACE_III_TTY is not set
+# CONFIG_USERIAL is not set
+# CONFIG_WATCHDOG is not set
 # CONFIG_UMISC is not set
 
 #
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
--- lx2.0/v2.0.21/linux/arch/m68k/fpsp040/skeleton.S	Mon May  6 12:44:30 1996
+++ linux/arch/m68k/fpsp040/skeleton.S	Wed Sep 25 10:47:39 1996
@@ -46,15 +46,6 @@
 |
 |	The following counters are used for standalone testing
 |
-sigunimp:	.long	0
-sigbsun:		.long	0
-siginex:		.long	0
-sigdz:		.long	0
-sigunfl:		.long	0
-sigovfl:		.long	0
-sigoperr:	.long	0
-sigsnan:		.long	0
-sigunsupp:	.long	0
 
 	|section 8
  
@@ -85,8 +76,6 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	addl	#1,sigdz		|for standalone testing
-
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
@@ -160,8 +149,6 @@
 
 real_inex:
 
-	addl		#1,siginex		|for standalone testing
-
 	link		%a6,#-LOCAL_SIZE
 	fsave		-(%sp)
 not_fmt40:
@@ -203,8 +190,6 @@
 	jmp	fpsp_ovfl
 real_ovfl:
 
-	addl		#1,sigovfl		|for standalone testing
-
 	link		%a6,#-LOCAL_SIZE
 	fsave		-(%sp)
 	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
@@ -234,8 +219,6 @@
 	jmp	fpsp_unfl
 real_unfl:
 
-	addl		#1,sigunfl		|for standalone testing
-
 	link		%a6,#-LOCAL_SIZE
 	fsave		-(%sp)
 	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
@@ -270,8 +253,6 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	addl		#1,sigsnan		|for standalone testing
-
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
@@ -297,9 +278,6 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	addl		#1,sigoperr		|for standalone testing
-
-
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
@@ -331,10 +309,6 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	addl		#1,sigbsun		|for standalone testing
-
-
-
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
@@ -359,9 +333,6 @@
 	jmp	fpsp_fline
 real_fline:
 
-	addl		#1,sigunimp		|for standalone testing
-
-
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
@@ -386,9 +357,6 @@
 	bclrb		#E1,E_BYTE(%a6)	|unsupp is always an E1 exception
 	frestore	(%sp)+
 	unlk		%a6
-
-	addl		#1,sigunsupp		|for standalone testing
-
 
 	SAVE_ALL
 	moveq	#-1,%d0
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/Makefile linux/arch/m68k/ifpsp060/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/Makefile	Tue Apr 23 17:14:22 1996
+++ linux/arch/m68k/ifpsp060/Makefile	Wed Sep 25 10:47:39 1996
@@ -4,15 +4,9 @@
 # License.  See the file "README.legal" in the main directory of this archive
 # for more details.
 
-#.c.s:
-#	$(CC) $(CFLAGS) -S $<
-#.c.o:
-#	$(CC) $(CFLAGS) -c $<
-#.s.o:
-#	$(AS) -o $*.o $<
 .S.o:
-	$(AS) -o $*.o $<
-#	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+#	$(AS) -o $*.o $<
+	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 OS_TARGET := ifpsp.o
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/fskeleton.S linux/arch/m68k/ifpsp060/fskeleton.S
--- lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/fskeleton.S	Tue Apr 23 17:14:22 1996
+++ linux/arch/m68k/ifpsp060/fskeleton.S	Wed Sep 25 10:47:39 1996
@@ -34,6 +34,7 @@
 |	(3) example "Call-out" table
 |
 
+#include <linux/linkage.h>
 
 |################################
 | (1) EXAMPLE CALL-OUTS		#
@@ -61,7 +62,7 @@
 |
 	.global		_060_fpsp_done
 _060_fpsp_done:
-	rte
+	bral	 _060_isp_done	| do the same as isp_done
 
 |
 | _060_real_ovfl():
@@ -79,7 +80,8 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
+
 
 |
 | _060_real_unfl():
@@ -97,7 +99,7 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_operr():
@@ -116,7 +118,7 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_snan():
@@ -135,7 +137,7 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_dz():
@@ -154,7 +156,7 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_inex():
@@ -173,7 +175,7 @@
 	fsave		-(%sp)
 	move.w		#0x6000,0x2(%sp)
 	frestore	(%sp)+
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_bsun():
@@ -189,14 +191,13 @@
 |
 	.global		_060_real_bsun
 _060_real_bsun:
-	fsave		-(%sp)
+|	fsave		-(%sp)
 
 	fmove.l		%fpsr,-(%sp)
 	andi.b		#0xfe,(%sp)
 	fmove.l		(%sp)+,%fpsr
 
-	add.l		#0xc,%sp
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_fline():
@@ -210,7 +211,7 @@
 | 
 	.global		_060_real_fline
 _060_real_fline:
-	bras		_060_real_fline
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_fpu_disabled():
@@ -230,11 +231,9 @@
 	.global		_060_real_fpu_disabled
 _060_real_fpu_disabled:
 	move.l		%d0,-(%sp)		| enabled the fpu
-	.long	0x4E7A0808
-	|movec		pcr,d0
+	.long	0x4E7A0808			|movec		pcr,%d0
 	bclr		#0x1,%d0
-	.long	0x4E7B0808
-	|movec		%d0,pcr
+	.long	0x4E7B0808			|movec		%d0,pcr
 	move.l		(%sp)+,%d0
 
 	move.l		0xc(%sp),0x2(%sp)	| set "Current PC"
@@ -251,7 +250,7 @@
 |
 	.global		_060_real_trap
 _060_real_trap:
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |############################################################################
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/iskeleton.S	Fri Apr 26 12:12:35 1996
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Wed Sep 25 10:47:39 1996
@@ -34,6 +34,15 @@
 |	(3) example "Call-out" table
 |
 
+#include <linux/linkage.h>
+
+LOFF_ORIG_D0	= 0x20
+
+#define SAVE_ALL				\
+	clrl	%sp@-;     /* stk_adj */	\
+	movel	%d0,%sp@-; /* orig d0 */	\
+	movel	%d0,%sp@-; /* d0 */		\
+	moveml	%d1-%d5/%a0-%a1,%sp@-
 
 |################################
 | (1) EXAMPLE CALL-OUTS 	#
@@ -61,9 +70,22 @@
 | To simply continue execution at the next instruction, just
 | do an "rte".
 |
+| Linux/68k: If returning to user space, check for needed reselections.
+
 	.global		_060_isp_done
 _060_isp_done:
+	btst	#0x5,%sp@		| supervisor bit set in saved SR?
+	beq	Lnotkern
 	rte
+Lnotkern:
+	tstl	SYMBOL_NAME(need_resched)
+	bne	Lmustsched
+	rte
+Lmustsched:
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
 
 |
 | _060_real_chk():
@@ -71,13 +93,15 @@
 | This is an alternate exit point for the Unimplemented Integer
 | Instruction exception handler. If the instruction was a "chk2"
 | and the operand was out of bounds, then _isp_unimp() creates
-| a CHK exception stack frame from the Unimplemented Integer Instruction
+| a CHK exception stack frame from the Unimplemented Integer Instrcution
 | stack frame and branches to this routine.
 |
+| Linux/68k: commented out test for tracing
+
 	.global		_060_real_chk
 _060_real_chk:
-	tst.b		(%sp)			| is tracing enabled?
-	bpls		real_chk_end		| no
+|	tst.b		(%sp)			| is tracing enabled?
+|	bpls		real_chk_end		| no
 
 |
 |	    CHK FRAME		   TRACE FRAME
@@ -92,11 +116,11 @@
 |	*      SR	*	*      SR	*
 |	*****************	*****************
 |
-	move.b		#0x24,0x7(%sp)		| set trace vecno
-	bral		_060_real_trace
+|	move.b		#0x24,0x7(%sp)		| set trace vecno
+|	bral		_060_real_trace
 
 real_chk_end:
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |
 | _060_real_divbyzero:
@@ -112,10 +136,12 @@
 | then it create a Trace exception stack frame from the "chk" exception
 | stack frame and branches to the _real_trace() entry point.
 | 
+| Linux/68k: commented out test for tracing
+
 	.global		_060_real_divbyzero
 _060_real_divbyzero:
-	tst.b		(%sp)			| is tracing enabled?
-	bpls		real_divbyzero_end	| no
+|	tst.b		(%sp)			| is tracing enabled?
+|	bpls		real_divbyzero_end	| no
 
 |
 |	 DIVBYZERO FRAME	   TRACE FRAME
@@ -130,11 +156,11 @@
 |	*      SR	*	*      SR	*
 |	*****************	*****************
 |
-	move.b		#0x24,0x7(%sp)		| set trace vecno
-	bral		_060_real_trace
+|	move.b		#0x24,0x7(%sp)		| set trace vecno
+|	bral		_060_real_trace
 
 real_divbyzero_end:
-	rte
+	bral		SYMBOL_NAME(trap)	| jump to trap handler
 
 |##########################
 
@@ -177,6 +203,9 @@
 | Expected outputs:
 |	d0 = 0 -> success; non-zero -> failure
 |
+| Linux/68k: As long as ints are disabled, no swapping out should
+| occur (hopefully...)
+|
 	.global		_060_real_lock_page
 _060_real_lock_page:
 	clr.l		%d0
@@ -194,6 +223,9 @@
 |	d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user
 |	d1 = `xxxxxxff -> longword; `xxxxxx00 -> word
 |
+| Linux/68k: As we do no special locking operation, also no unlocking
+| is needed...
+
 	.global		_060_real_unlock_page
 _060_real_unlock_page:
 	clr.l		%d0
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/os.S linux/arch/m68k/ifpsp060/os.S
--- lx2.0/v2.0.21/linux/arch/m68k/ifpsp060/os.S	Tue Apr 23 17:14:22 1996
+++ linux/arch/m68k/ifpsp060/os.S	Wed Sep 25 10:47:39 1996
@@ -32,6 +32,7 @@
 |	- example "Call-Out"s required by both the ISP and FPSP.
 |
 
+#include <linux/linkage.h>
 
 |################################
 | EXAMPLE CALL-OUTS 		#
@@ -64,6 +65,10 @@
 | The result is that Unix processes are allowed to sleep as a consequence
 | of a page fault during a _copyout.
 |
+| Linux/68k: The _060_[id]mem_{read,write}_{byte,word,long} functions
+| (i.e. all the known length <= 4) are implemented by single moves
+| statements instead of (more expensive) copy{in,out} calls, if
+| working in user space
 
 |
 | _060_dmem_write():
@@ -147,18 +152,12 @@
 _060_dmem_read_byte:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmrbs			| supervisor
-dmrbu:	clr.l		-(%sp)			| clear space on stack for result
-	move.l		#0x1,-(%sp)		| pass: # bytes to copy
-	pea		0x7(%sp)		| pass: dst addr (stack)
-	move.l		%a0,-(%sp)		| pass: src addr (user mem)
-	bsr.l		_copyin			| "copy in" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0xc,%sp		| delete params
-	move.l		(%sp)+,%d0		| put answer in d0
-	rts
+dmrbu:	clr.l		%d0			| clear whole longword
+	movs.b		(%a0),%d0		| fetch user byte
+	bras		dmrbr
 dmrbs:	clr.l		%d0			| clear whole longword
 	move.b		(%a0),%d0		| fetch super byte
-	clr.l		%d1			| return success
+dmrbr:	clr.l		%d1			| return success
 	rts
 
 |
@@ -173,22 +172,29 @@
 |	d0 - data word in d0
 |	d1 - 0 = success, !0 = failure
 |
+| _060_imem_read_word():
+| 
+| Read an instruction word from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - instruction word in d0
+|	d1 - 0 = success, !0 = failure
+|
 	.global 		_060_dmem_read_word
+	.global 		_060_imem_read_word
 _060_dmem_read_word:
+_060_imem_read_word:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmrws			| supervisor
-dmrwu:	clr.l		-(%sp)			| clear space on stack for result
-	move.l		#0x2,-(%sp)		| pass: # bytes to copy
-	pea		0x6(%sp)		| pass: dst addr (stack)
-	move.l		%a0,-(%sp)		| pass: src addr (user mem)
-	bsr.l		_copyin			| "copy in" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0xc,%sp		| delete params
-	move.l		(%sp)+,%d0		| put answer in d0
-	rts
+dmrwu:	clr.l		%d0			| clear whole longword
+	movs.w		(%a0), %d0		| fetch user word
+	bras		dmrwr
 dmrws:	clr.l		%d0			| clear whole longword
 	move.w		(%a0), %d0		| fetch super word
-	clr.l		%d1			| return success
+dmrwr:	clr.l		%d1			| return success
 	rts
 
 |
@@ -203,21 +209,27 @@
 |	d0 - data longword in d0
 |	d1 - 0 = success, !0 = failure
 |
+| _060_imem_read_long():
+| 
+| Read an instruction longword from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - instruction longword in d0
+|	d1 - 0 = success, !0 = failure
+|
 	.global 		_060_dmem_read_long
+	.global 		_060_imem_read_long
 _060_dmem_read_long:
+_060_imem_read_long:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmrls			| supervisor
-dmrlu:	subq.l		#0x4,%sp		| clear space on stack for result
-	move.l		#0x4,-(%sp)		| pass: # bytes to copy
-	pea		0x4(%sp)		| pass: dst addr (stack)
-	move.l		%a0,-(%sp)		| pass: src addr (user mem)
-	bsr.l		_copyin			| "copy in" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0xc,%sp		| delete params
-	move.l		(%sp)+,%d0		| put answer in d0
-	rts
+dmrlu:	movs.l		(%a0),%d0		| fetch user longword
+	bras		dmrlr
 dmrls:	move.l		(%a0),%d0		| fetch super longword
-	clr.l		%d1			| return success
+dmrlr:	clr.l		%d1			| return success
 	rts
 
 |
@@ -236,16 +248,10 @@
 _060_dmem_write_byte:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmwbs			| supervisor
-dmwbu:	move.l		%d0,-(%sp)		| put src on stack
-	move.l		#0x1,-(%sp)		| pass: # bytes to copy
-	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
-	pea		0xb(%sp)		| pass: src addr (stack)
-	bsr.l		_copyout		| "copy out" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0x10,%sp		| delete params + src
-	rts
+dmwbu:	movs.b		%d0,(%a0)		| store user byte
+	bras		dmwbr
 dmwbs:	move.b		%d0,(%a0)		| store super byte
-	clr.l		%d1			| return success
+dmwbr:	clr.l		%d1			| return success
 	rts
 
 |
@@ -264,16 +270,10 @@
 _060_dmem_write_word:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmwws			| supervisor
-dmwwu:	move.l		%d0,-(%sp)		| put src on stack
-	move.l		#0x2,-(%sp)		| pass: # bytes to copy
-	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
-	pea		0xa(%sp)		| pass: src addr (stack)
-	bsr.l		_copyout		| "copy out" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0x10,%sp		| delete params + src
-	rts
+dmwwu:	movs.w		%d0,(%a0)		| store user word
+	bras		dmwwr
 dmwws:	move.w		%d0,(%a0)		| store super word
-	clr.l		%d1			| return success
+dmwwr:	clr.l		%d1			| return success
 	rts
 
 |
@@ -292,75 +292,12 @@
 _060_dmem_write_long:
 	btst		#0x5,0x4(%a6)		| check for supervisor state
 	bnes		dmwls			| supervisor
-dmwlu:	move.l		%d0,-(%sp)		| put src on stack
-	move.l		#0x4,-(%sp)		| pass: # bytes to copy
-	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
-	pea		0x8(%sp)		| pass: src addr (stack)
-	bsr.l		_copyout		| "copy out" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0x10,%sp		| delete params + src
-	rts
+dmwlu:	movs.l		%d0,(%a0)		| store user longword
+	bra		dmwlr
 dmwls:	move.l		%d0,(%a0)		| store super longword
-	clr.l		%d1			| return success
-	rts
-
-|
-| _060_imem_read_word():
-| 
-| Read an instruction word from user memory.
-|
-| INPUTS:
-|	a0 - user source address
-| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
-| OUTPUTS:
-|	d0 - instruction word in d0
-|	d1 - 0 = success, !0 = failure
-|
-	.global 		_060_imem_read_word
-_060_imem_read_word:
-	btst		#0x5,0x4(%a6)		| check for supervisor state
-	bnes		imrws			| supervisor
-imrwu:	clr.l		-(%sp)			| clear space on stack for result
-	move.l		#0x2,-(%sp)		| pass: # bytes to copy
-	pea		0x6(%sp)		| pass: dst addr (stack)
-	move.l		%a0,-(%sp)		| pass: src addr (user mem)
-	bsr.l		_copyin			| "copy in" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0xc,%sp		| delete params
-	move.l		(%sp)+,%d0		| put answer in d0
-	rts
-imrws:	move.w		(%a0),%d0		| fetch super word
-	clr.l		%d1			| return success
+dmwlr:	clr.l		%d1			| return success
 	rts
 
-|
-| _060_imem_read_long():
-| 
-| Read an instruction longword from user memory.
-|
-| INPUTS:
-|	a0 - user source address
-| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
-| OUTPUTS:
-|	d0 - instruction longword in d0
-|	d1 - 0 = success, !0 = failure
-|
-	.global 		_060_imem_read_long
-_060_imem_read_long:
-	btst		#0x5,0x4(%a6)		| check for supervisor state
-	bnes		imrls			| supervisor
-imrlu:	subq.l		#0x4,%sp		| clear space on stack for result
-	move.l		#0x4,-(%sp)		| pass: # bytes to copy
-	pea		0x4(%sp)		| pass: dst addr (stack)
-	move.l		%a0,-(%sp)		| pass: src addr (user mem)
-	bsr.l		_copyin			| "copy in" the data
-	move.l		%d0,%d1			| return success
-	add.l		#0xc,%sp		| delete params
-	move.l		(%sp)+,%d0		| put answer in d0
-	rts
-imrls:	move.l		(%a0),%d0		| fetch super longword
-	clr.l		%d1			| return success
-	rts
 
 |###############################################
 
@@ -369,6 +306,10 @@
 | Assumes that D0/D1/A0/A1 are scratch registers. The _copyin/_copyout
 | below assume that the SFC/DFC have been set previously.
 |
+| Linux/68k: These are basically non-inlined versions of
+| memcpy_{to,from}fs, but without long-transfer optimization
+| Note: Assumed that SFC/DFC are pointing correctly to user data
+| space... Should be right, or are there any exceptions?
 
 |
 | int _copyout(supervisor_addr, user_addr, nbytes)
@@ -378,11 +319,12 @@
 	move.l		4(%sp),%a0		| source
 	move.l		8(%sp),%a1		| destination
 	move.l		12(%sp),%d0		| count
+    subq.l      #1,%d0
 moreout:
 	move.b		(%a0)+,%d1		| fetch supervisor byte
 	movs.b		%d1,(%a1)+		| store user byte
-	subq.l		#0x1,%d0		| are we through yet?
-	bne		moreout			| no; so, continue
+	dbra		%d0,moreout		| are we through yet?
+    moveq		#0,%d0			| return success
 	rts
 
 |
@@ -393,11 +335,13 @@
 	move.l		4(%sp),%a0		| source
 	move.l		8(%sp),%a1		| destination
 	move.l		12(%sp),%d0		| count
+    subq.l      #1,%d0
 morein:
 	movs.b		(%a0)+,%d1		| fetch user byte
 	move.b		%d1,(%a1)+		| write supervisor byte
 	subq.l		#0x1,%d0		| are we through yet?
-	bne		morein			| no; so, continue
+	dbra		%d0,morein		| are we through yet?
+    moveq		#0,%d0			| return success
 	rts
 
 |###########################################################################
@@ -413,7 +357,7 @@
 |
 	.global		_060_real_trace
 _060_real_trace:
-	rte
+	bral	SYMBOL_NAME(trap)
 
 |
 | _060_real_access():
@@ -429,4 +373,4 @@
 |
 	.global		_060_real_access
 _060_real_access:
-	rte
+	bral	SYMBOL_NAME(buserr)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/Makefile	Mon Apr  1 21:46:31 1996
+++ linux/arch/m68k/kernel/Makefile	Wed Sep 25 10:47:39 1996
@@ -8,13 +8,12 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ -traditional -Wa,-m68030 -c $< -o $*.o
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
 all: kernel.o head.o
 O_TARGET := kernel.o
 O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
-	  setup.o bios32.o sys_m68k.o console.o time.o
-OX_OBJS = ksyms.o
+	  setup.o bios32.o sys_m68k.o console.o time.o ksyms.o
 
 head.o: head.S
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/console.c	Mon May  6 12:26:02 1996
+++ linux/arch/m68k/kernel/console.c	Wed Sep 25 10:47:39 1996
@@ -80,7 +80,7 @@
  */
 
 #define BLANK 0x0020
-#undef CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
+#define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
 
 /* A bitmap for codes <32. A bit of 1 indicates that the code
  * corresponding to that bit number invokes some special action
@@ -175,6 +175,8 @@
        int do_poke_blanked_console = 0;
        int console_blanked = 0;
 static int blankinterval = 10*60*HZ;
+static int vesa_off_interval = 0;
+static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
 
 static struct vc {
 	struct vc_data *d;
@@ -537,7 +539,7 @@
  */
 static void gotoxy(int currcons, int new_x, int new_y)
 {
-	int max_y;
+	int min_y, max_y;
 
 	if (new_x < 0)
 		x = 0;
@@ -547,21 +549,28 @@
 		else
 			x = new_x;
  	if (decom) {
-		new_y += top;
+		min_y = top;
 		max_y = bottom;
-	} else
+	} else {
+		min_y = 0;
 		max_y = rows;
-	if (new_y < 0)
-		y = 0;
+	}
+	if (new_y < min_y)
+		y = min_y;
+	else if (new_y >= max_y)
+		y = max_y - 1;
 	else
-		if (new_y >= max_y)
-			y = max_y - 1;
-		else
-			y = new_y;
+		y = new_y;
 	pos = video_mem_start + y * cols + x;
 	need_wrap = 0;
 }
 
+/* for absolute user moves, when decom is set */
+static void gotoxay(int currcons, int new_x, int new_y)
+{
+	gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
+}
+
 static void hide_cursor(int currcons)
 {
 	sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
@@ -1144,7 +1153,7 @@
 				break;
 			case 6:			/* Origin relative/absolute */
 				decom = on_off;
-				gotoxy(currcons,0,0);
+				gotoxay(currcons,0,0);
 				break;
 			case 7:			/* Autowrap on/off */
 				decawm = on_off;
@@ -1227,6 +1236,9 @@
 		case 13: /* unblank the screen */
 			unblank_screen();
 			break;
+		case 14: /* set vesa powerdown interval */
+			vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			break;
 	}
 }
 
@@ -1516,34 +1528,34 @@
 		    tc = translate[toggle_meta ? (c|0x80) : c];
 		}
 
-		/* If the original code was < 32 we only allow a
-		 * glyph to be displayed if the code is not normally
-		 * used (such as for cursor movement) or if the
-		 * disp_ctrl mode has been explicitly enabled.
-		 * Note: ESC is *never* allowed to be displayed as
-		 * that would disable all escape sequences!
-		 * To display font position 0x1B, go into UTF mode
-		 * and display character U+F01B, or change the mapping.
-		 */
-		ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS
-					    : CTRL_ACTION) >> c) & 1))));
+                /* If the original code was a control character we
+                 * only allow a glyph to be displayed if the code is
+                 * not normally used (such as for cursor movement) or
+                 * if the disp_ctrl mode has been explicitly enabled.
+                 * Certain characters (as given by the CTRL_ALWAYS
+                 * bitmap) are always displayed as control characters,
+                 * as the console would be pretty useless without
+                 * them; to display an arbitrary font position use the
+                 * direct-to-font zone in UTF-8 mode.
+                 */
+                ok = tc && (c >= 32 ||
+                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
+                                         : CTRL_ACTION) >> c) & 1)))
+                        && (c != 127 || disp_ctrl);
 
 		if (vc_state == ESnormal && ok) {
 			/* Now try to find out how to display it */
 			tc = conv_uni_to_pc(tc);
-			if ( tc == -4 )
-			  {
-			    /* If we got -4 (not found) then see if we have
-			       defined a replacement character (U+FFFD) */
-			    tc = conv_uni_to_pc(0xfffd);
-			  }
-			else if ( tc == -3 )
-			  {
-			    /* Bad hash table -- hope for the best */
-			    tc = c;
-			  }
+			if ( tc == -4 ) {
+                                /* If we got -4 (not found) then see if we have
+                                   defined a replacement character (U+FFFD) */
+                                tc = conv_uni_to_pc(0xfffd);
+                        } else if ( tc == -3 ) {
+                                /* Bad hash table -- hope for the best */
+                                tc = c;
+                        }
 			if (tc & ~console_charmask)
-			  continue; /* Conversion failed */
+				continue; /* Conversion failed */
 
 			if (need_wrap) {
 				cr(currcons);
@@ -1851,12 +1863,12 @@
 				continue;
 			    case 'd':
 				if (par[0]) par[0]--;
-				gotoxy(currcons,x,par[0]);
+				gotoxay(currcons,x,par[0]);
 				continue;
 			    case 'H': case 'f':
 				if (par[0]) par[0]--;
 				if (par[1]) par[1]--;
-				gotoxy(currcons,par[1],par[0]);
+				gotoxay(currcons,par[1],par[0]);
 				continue;
 			    case 'J':
 				csi_J(currcons,par[0]);
@@ -1907,7 +1919,7 @@
 				    par[1] <= rows) {
 					top=par[0]-1;
 					bottom=par[1];
-					gotoxy(currcons,0,0);
+					gotoxay(currcons,0,0);
 				}
 				continue;
 			    case 's':
@@ -2258,6 +2270,29 @@
 	return kmem_start;
 }
 
+void vesa_powerdown_screen(void)
+{
+	int currcons = fg_console;
+
+	timer_active &= ~(1<<BLANK_TIMER);
+	timer_table[BLANK_TIMER].fn = unblank_screen;
+
+	/* Power down if currently suspended (1 or 2),
+	 * suspend if currently blanked (0),
+	 * else do nothing (i.e. already powered down (3)).
+	 * Called only if powerdown features are allowed.
+	 */
+	switch (vesa_blank_mode) {
+	case 0:
+		sw->con_blank(2);
+		break;
+	case 1:
+	case 2:
+		sw->con_blank(4);
+		break;
+	}
+}
+
 void do_blank_screen(int nopowersave)
 {
 	int currcons;
@@ -2273,14 +2308,22 @@
 
 	/* don't blank graphics */
 	if (vt_cons[fg_console]->vc_mode == KD_TEXT) {
-		timer_active &= ~(1<<BLANK_TIMER);
-		timer_table[BLANK_TIMER].fn = unblank_screen;
+		if (vesa_off_interval && !nopowersave) {
+			timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
+			timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
+			timer_active |= (1<<BLANK_TIMER);
+		} else {
+			timer_active &= ~(1<<BLANK_TIMER);
+			timer_table[BLANK_TIMER].fn = unblank_screen;
+		}
 
 		/* try not to lose information by blanking,
 		   and not to waste memory */
 		currcons = fg_console;
 		has_scrolled = 0;
-		sw->con_blank (1);
+		sw->con_blank(1);
+		if (!nopowersave)
+			sw->con_blank(vesa_blank_mode + 1);
 	}
 	else
 		hide_cursor(fg_console);
@@ -2413,89 +2456,56 @@
 /*
  * PIO_FONT support.
  *
- * The font loading code goes back to the codepage package by
- * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
- * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
- * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
- *
- * Change for certain monochrome monitors by Yury Shevchuck
- * (sizif@botik.yaroslavl.su).
+ * Currently we only support 8 pixels wide fonts, at a maximum height
+ * of 32 pixels. Userspace fontdata is stored with 32 bytes reserved
+ * for each character which is kinda wasty, but this is done in order
+ * to maintain compatibility with the EGA/VGA fonts. It is upto the
+ * actual low-level console-driver convert data into its favorite
+ * format (maybe we should add a `fontoffset' field to the `display'
+ * structure so we wont have to convert the fontdata all the time.
+ * /Jes
  */
 
-#define colourmap ((char *)0xa0000)
-/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
-   should use 0xA0000 for the bwmap as well.. */
-#define blackwmap ((char *)0xa0000)
 #define cmapsz 8192
-#define seq_port_reg (0x3c4)
-#define seq_port_val (0x3c5)
-#define gr_port_reg (0x3ce)
-#define gr_port_val (0x3cf)
 
-static int set_get_font(char * arg, int set)
+static int set_get_font(char * arg, int set, int ch512)
 {
 #ifdef CAN_LOAD_EGA_FONTS
-	int i;
+	int i, unit, size;
 	char *charmap;
-	int beg;
-
-	/* no use to "load" CGA... */
 
-	if (video_type == VIDEO_TYPE_EGAC) {
-		charmap = colourmap;
-		beg = 0x0e;
-	} else if (video_type == VIDEO_TYPE_EGAM) {
-		charmap = blackwmap;
-		beg = 0x0a;
-	} else
+	if (arg){
+		i = verify_area(set ? VERIFY_READ : VERIFY_WRITE,
+				(void *)arg, ch512 ? 2*cmapsz : cmapsz);
+		if (i)
+			return i;
+	}else
 		return -EINVAL;
 
-	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
-	if (i)
-		return i;
 
-	cli();
-	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
-	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
-	outb_p( 0x02, seq_port_reg );
-	outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
-	outb_p( 0x04, seq_port_reg );
-	outb_p( 0x07, seq_port_val );   /* Sequential addressing */
-	outb_p( 0x00, seq_port_reg );
-	outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
-
-	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
-	outb_p( 0x02, gr_port_val );    /* select map 2 */
-	outb_p( 0x05, gr_port_reg );
-	outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
-	outb_p( 0x06, gr_port_reg );
-	outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
-	sti();
+	size = ch512 ? 2*cmapsz : cmapsz;
 
-	if (set)
-		memcpy_fromfs (charmap, arg, cmapsz);
-	else
-		memcpy_tofs (arg, charmap, cmapsz);
+	charmap = (char *)kmalloc(size, GFP_USER);
 
-	cli();
-	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
-	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
-	outb_p( 0x02, seq_port_reg );
-	outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
-	outb_p( 0x04, seq_port_reg );
-	outb_p( 0x03, seq_port_val );   /* odd-even addressing */
-	outb_p( 0x00, seq_port_reg );
-	outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
-
-	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
-	outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
-	outb_p( 0x05, gr_port_reg );
-	outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
-	outb_p( 0x06, gr_port_reg );
-	outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
-	sti();
+	if (set){
+		memcpy_fromfs(charmap, arg, size);
 
-	return 0;
+		for (unit = 32; unit > 0; unit--)
+			for (i = 0; i < (ch512 ? 512 : 256); i++)
+				if (charmap[32*i+unit-1])
+					goto nonzero;
+	nonzero:
+		i = conswitchp->con_set_font(vc_cons[fg_console].d, 8,
+					     unit, charmap);
+	}else{
+		memset(charmap, 0, size);
+		i = conswitchp->con_get_font(vc_cons[fg_console].d,
+					     &unit, &unit, charmap);
+		memcpy_tofs(arg, charmap, size);
+	}
+	kfree(charmap);
+
+	return i;
 #else
 	return -EINVAL;
 #endif
@@ -2530,15 +2540,22 @@
  * 8xH fonts (0 < H <= 32).
  */
 
-int con_set_font (char *arg)
+int con_set_font (char *arg, int ch512)
 {
-	hashtable_contents_valid = 0;
-	return set_get_font (arg,1);
+	int i;
+
+	i = set_get_font (arg,1,ch512);
+  	if ( !i ) {
+		hashtable_contents_valid = 0;
+      		video_mode_512ch = ch512;
+      		console_charmask = ch512 ? 0x1ff : 0x0ff;
+	}
+	return i;
 }
 
 int con_get_font (char *arg)
 {
-	return set_get_font (arg,0);
+	return set_get_font (arg,0,video_mode_512ch);
 }
 
 /*
@@ -2554,6 +2571,9 @@
 
 void set_vesa_blanking(int arg)
 {
+	char *argp = (char *)arg + 1;
+	unsigned int mode = get_fs_byte(argp);
+	vesa_blank_mode = (mode < 4) ? mode : 0;
 }
 
 unsigned long get_video_num_lines(unsigned int currcons)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/entry.S	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/kernel/entry.S	Wed Sep 25 10:47:39 1996
@@ -8,7 +8,9 @@
  * License.  See the file README.legal in the main directory of this archive
  * for more details.
  *
- * 680x0 support by Hamish Macdonald
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
  *
  */
 
@@ -46,11 +48,11 @@
  */
 
 #include <linux/sys.h>
-
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/setup.h>
 #include <asm/segment.h>
 
-LCF_MASK	= 0x0001
-
 LENOSYS = 38
 
 /*
@@ -62,18 +64,16 @@
 LTASK_SIGNAL	= 12
 LTASK_BLOCKED	= 16
 LTASK_FLAGS	= 20
-LTASK_ERRNO	= 24
-
-#include <linux/config.h>
-#include <linux/linkage.h>
 
 /* the following macro is used when enabling interrupts */
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+#if defined(CONFIG_ATARI_ONLY)
 	/* block out HSYNC on the atari */
 #define ALLOWINT 0xfbff
+#define	MAX_NOINT_IPL	3
 #else
 	/* portable version */
 #define ALLOWINT 0xf8ff
+#define	MAX_NOINT_IPL	0
 #endif /* machine compilation types */ 
 
 LD0		= 0x1C
@@ -164,23 +164,12 @@
 	lea	SYMBOL_NAME(sys_call_table),%a0
 	movel	%a0@(%d2:l:4),%d3
 	jeq	SYMBOL_NAME(ret_from_exception)
-	andw	#~LCF_MASK,%sp@(LSR)	| assume syscall success
 	movel	SYMBOL_NAME(current_set),%a0
-	clrl	%a0@(LTASK_ERRNO)
 	btst	#5,%a0@(LTASK_FLAGS+3)	| PF_TRACESYS
 	bnes	1f
 	movel	%d3,%a0
 	jbsr	%a0@
 	movel	%d0,%sp@(LD0)		| save the return value
-	jpl	2f
-	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
-2:
-	movel	SYMBOL_NAME(current_set),%a0
-	movel	%a0@(LTASK_ERRNO),%d1
-	negl	%d1
-	jeq	SYMBOL_NAME(ret_from_exception)
-	movel	%d1,%sp@(LD0)
-	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
 	jra	SYMBOL_NAME(ret_from_exception)
 1:
 	subql	#4,%sp
@@ -191,16 +180,7 @@
 	movel	%d3,%a0
 	jbsr	%a0@
 	movel	%d0,%sp@(LD0)		| save the return value
-	jpl	2f
-	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
-2:
-	movel	SYMBOL_NAME(current_set),%a0
-	movel	%a0@(LTASK_ERRNO),%d1
-	negl	%d1
-	jeq	2f
-	movel	%d1,%sp@(LD0)
-	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
-2:	subql	#4,%sp			| dummy return address
+	subql	#4,%sp			| dummy return address
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(syscall_trace)
 
@@ -225,19 +205,21 @@
 	jbsr	SYMBOL_NAME(send_sig)
 	addql	#8,%sp
 	addql	#4,%sp
+	movel	SYMBOL_NAME(current_set),%a0
 
 1:
-	moveq	#0,%d0
-	movel	SYMBOL_NAME(current_set),%a0
-	cmpl	%a0@(LTASK_STATE),%d0     | state
+	tstl	%a0@(LTASK_STATE)	| state
 	jne	SYMBOL_NAME(reschedule)
-	cmpl	%a0@(LTASK_COUNTER),%d0   | counter
+	tstl	%a0@(LTASK_COUNTER)	| counter
 	jeq	SYMBOL_NAME(reschedule)
 
 	movel	%a0@(LTASK_BLOCKED),%d0
 	movel	%d0,%d1			| save blocked in d1 for sig handling
 	notl	%d0
-	andl	%a0@(LTASK_SIGNAL),%d0
+	btst	#4,%a0@(LTASK_FLAGS+3)	| PF_PTRACED
+	jeq	1f
+	moveq	#-1,%d0			| let the debugger see all signals
+1:	andl	%a0@(LTASK_SIGNAL),%d0
 	jne	Lsignal_return
 2:	RESTORE_ALL
 
@@ -261,13 +243,11 @@
 	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
-	
 	addql	#1,SYMBOL_NAME(intr_count)
+					|  put exception # in d0
+	bfextu %sp@(LFORMATVEC){#4,#10},%d0
 
-	movew	%sp@(LFORMATVEC),%d0      |  put exception # in d0
-	andil	#0xfff,%d0		|  mask out format nybble
-
-	movel	%sp,%sp@-		
+	movel	%sp,%sp@-
 	movel	%d0,%sp@- 		|  put vector # on stack
 	jbsr	SYMBOL_NAME(process_int)|  process the IRQ
 	addql	#8,%sp			|  pop parameters off stack
@@ -275,27 +255,27 @@
 SYMBOL_NAME_LABEL(ret_from_interrupt)
 	/* check if we need to do software interrupts */
 1:
-	movel	SYMBOL_NAME(intr_count),%d2
-	subql	#1,%d2
-	jne	2f
-
+	movel	SYMBOL_NAME(intr_count),%d1
+	subql	#1,%d1
+	jne	4f
+	bfextu  %sp@(LSR){#5,#3},%d0    | Check for nested interrupt.
+#if MAX_NOINT_IPL > 0
+	cmpiw	#MAX_NOINT_IPL,%d0
+#endif
+	jhi	4f
+2:
 	movel	SYMBOL_NAME(bh_active),%d0
 	andl	SYMBOL_NAME(bh_mask),%d0
 	jne	3f
 
-	movel	%d2,SYMBOL_NAME(intr_count)
-
+	clrl	SYMBOL_NAME(intr_count)	| deliver signals, reschedule etc..
 	jra	SYMBOL_NAME(ret_from_exception)
-					| deliver signals, reschedule etc..
-
-2:	movel	%d2,SYMBOL_NAME(intr_count)
-	RESTORE_ALL
-3:
-	movew	%sr,%sp@-
-	andiw	#(ALLOWINT),%sr		| allow interrupts
+3:	
 	jbsr	SYMBOL_NAME(do_bottom_half)
-	movew	%sp@+,%sr
-	jra	1b
+	jbra	2b
+4:
+	movel	%d1,SYMBOL_NAME(intr_count)
+	RESTORE_ALL
 
 
 /* Handler for uninitialized and spurious interrupts */
@@ -335,7 +315,6 @@
 	rts
 
 LFLUSH_I_AND_D = 0x00000808
-LBI_CPU = 4
 LTSS_KSP	= 0
 LTSS_USP	= 4
 LTSS_SR		= 8
@@ -345,17 +324,16 @@
 
 SYMBOL_NAME_LABEL(resume)
 	/*
-	 * Beware - when entering resume, offset of tss is in a1 and
-	 * next (the new task) is in d1, so don't chance these
-	 * registers before their contents have been used.
+	 * Beware - when entering resume, offset of tss is in d1,
+	 * prev (the current task) is in a0, next (the new task)
+	 * is in a1 and d2.b is non-zero if the mm structure is
+	 * shared between the tasks, so don't change these
+	 * registers until their contents are no longer needed.
 	 */
-	
-	/* current tasks task_struct */
- 	movel	SYMBOL_NAME(current_set),%a0
 
 	/* offset of tss struct (processor state) from beginning
 	   of task struct */
-	addl	%a1,%a0
+	addl	%d1,%a0
 
 	/* save sr */
 	movew	%sr,%a0@(LTSS_SR)
@@ -372,11 +350,6 @@
 	movec	%usp,%d0
 	movel	%d0,%a0@(LTSS_USP)
 
-	/* load new task (before adjusting stack) */
-	/* The task has already been put in d1 by switch_to (Jes) */
-/*
-	movel	%sp@(4),%d1
-*/
 	/* save non-scratch registers on stack */
 	SAVE_SWITCH_STACK
 
@@ -385,41 +358,59 @@
 
 	/* save floating point context */
 	fsave	%a0@(LTSS_FPCTXT+27*4)
-	tstb	%a0@(LTSS_FPCTXT+27*4)
-	jeq	1f
-	fmovemx	%fp0-%fp7,%a0@(LTSS_FPCTXT)
+
+#if defined(CONFIG_M68060)
+#if !defined(CONFIG_M68060_ONLY)
+	btst	#3,SYMBOL_NAME(boot_info)+BI_cputype+3
+	beqs	1f
+#endif
+	/* The 060 FPU keeps status in bits 15-8 of the first longword */
+	tstb	%a0@(LTSS_FPCTXT+27*4+2)
+	jeq	3f
+#if !defined(CONFIG_M68060_ONLY)
+	jra	2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CONFIG_M68060_ONLY)
+1:	tstb	%a0@(LTSS_FPCTXT+27*4)
+	jeq	3f
+#endif
+2:	fmovemx	%fp0-%fp7,%a0@(LTSS_FPCTXT)
 	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4)
-1:
+3:
 
-	/* get pointer to tss struct (d1 contains new task) */
-	movel	%d1,SYMBOL_NAME(current_set)
-	movel	%d1,%a0
-	addl	%a1,%a0
+	/* get pointer to tss struct (a1 contains new task) */
+	movel	%a1,SYMBOL_NAME(current_set)
+	addl	%d1,%a1
+
+	/* Skip address space switching if they are the same. */
+	tstb	%d2
+	jne	4f
 
+#if defined(CONFIG_M68020_OR_M68030) && defined(CONFIG_M68040_OR_M68060)
 	/* 68040 or 68060 ? */
-	btst	#2,SYMBOL_NAME(boot_info)+LBI_CPU+3
-	bnes	1f
-	btst	#3,SYMBOL_NAME(boot_info)+LBI_CPU+3
+	tstl	SYMBOL_NAME(m68k_is040or060)
 	bnes	1f
-
+#endif
+#if defined(CONFIG_M68020_OR_M68030)
 	/*
 	 * switch address space
 	 */
 
 	/* flush MC68030/MC68020 caches (they are virtually addressed) */
 	movec	%cacr,%d0
-	oril	#LFLUSH_I_AND_D,%d0
+	oriw	#LFLUSH_I_AND_D,%d0
 	movec	%d0,%cacr
 
 	/* switch the root pointer */
-	pmove	%a0@(LTSS_CRP),%crp
-
-	/* flush address translation cache (probably not needed */
-	pflusha
+	pmove	%a1@(LTSS_CRP),%crp
+#endif
 
+#if defined(CONFIG_M68020_OR_M68030) && defined(CONFIG_M68040_OR_M68060)
 	jra	2f	/* skip m68040 stuff */
-
 1:
+#endif
+#if defined(CONFIG_M68040_OR_M68060)
 	/*
 	 * switch address space
 	 */
@@ -428,42 +419,60 @@
 	.word	0xf510			/* pflushan */
 
 	/* switch the root pointer */
-	movel	%a0@(LTSS_CRP+4),%d0
+	movel	%a1@(LTSS_CRP+4),%d0
 	.long	0x4e7b0806		/* movec d0,urp */
 
+#if defined (CONFIG_M68060)
 	/* is it a '060 ? */
-	btst	#3,SYMBOL_NAME(boot_info)+LBI_CPU+3
+	btst	#3,SYMBOL_NAME(boot_info)+BI_cputype+3
 	beqs	2f
 	/* clear user entries in the branch cache */
 	movec	%cacr,%d0
 	orl	#0x00200000,%d0
 	movec	%d0,%cacr
-
+#endif /* CONFIG_M68060 */
+#endif /* CONFIG_M68040_OR_M68060 */
 2:
+4:
 	/* restore floating point context */
-	tstb	%a0@(LTSS_FPCTXT+27*4)
-	jeq	1f
-	fmovemx	%a0@(LTSS_FPCTXT),%fp0-%fp7
-	fmoveml	%a0@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar
-1:	frestore %a0@(LTSS_FPCTXT+27*4)
+
+#if defined(CONFIG_M68060)
+#if !defined(CONFIG_M68060_ONLY)
+	btst	#3,SYMBOL_NAME(boot_info)+BI_cputype+3
+	beqs	1f
+#endif
+	/* The 060 FPU keeps status in bits 15-8 of the first longword */
+	tstb	%a1@(LTSS_FPCTXT+27*4+2)
+	jeq	3f
+#if !defined(CONFIG_M68060_ONLY)
+	jra	2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CONFIG_M68060_ONLY)
+1:	tstb	%a1@(LTSS_FPCTXT+27*4)
+	jeq	3f
+#endif	
+2:	fmovemx	%a1@(LTSS_FPCTXT),%fp0-%fp7
+	fmoveml	%a1@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar
+3:	frestore %a1@(LTSS_FPCTXT+27*4)
 
 	/* restore the kernel stack pointer */
-	movel	%a0@(LTSS_KSP),%sp
+	movel	%a1@(LTSS_KSP),%sp
 
 	/* restore non-scratch registers */
 	RESTORE_SWITCH_STACK
 
 	/* restore user stack pointer */
-	movel	%a0@(LTSS_USP),%d0
-	movec	%d0,%usp
+	movel	%a1@(LTSS_USP),%a0
+	movel	%a0,%usp
 
 	/* restore fs (sfc,%dfc) */
-	movew	%a0@(LTSS_FS),%a1
-	movec	%a1,%sfc
-	movec	%a1,%dfc
+	movew	%a1@(LTSS_FS),%a0
+	movec	%a0,%sfc
+	movec	%a0,%dfc
 
 	/* restore status register */
-	movew	%a0@(LTSS_SR),%sr
+	movew	%a1@(LTSS_SR),%sr
 
 	rts
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/head.S	Sat May 18 11:15:10 1996
+++ linux/arch/m68k/kernel/head.S	Wed Sep 25 10:47:39 1996
@@ -14,7 +14,7 @@
 ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
 ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
 ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
-** 96/04/26 G|nther Kelleter: fixed identity mapping for Falcon with
+** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
 ** 			      Magnum- and FX-alternate ram
 **
 ** This file is subject to the terms and conditions of the GNU General Public
@@ -65,9 +65,9 @@
  *   d4 - machine type
  */
 
-#include <linux/autoconf.h>
+#include <linux/config.h>
 #include <linux/linkage.h>
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/pgtable.h>
 
 .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
@@ -197,7 +197,7 @@
 	btst	#CPUB_68060,%d0
 	jeq	1f
 	/* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
-	movel	#D6F_060+_PAGE_NOCACHE,%d6
+	movel	#D6F_060+_PAGE_CACHE040W,%d6
 	jra	2f
 1:	btst	#CPUB_68040,%d0
 	jeq	1f
@@ -604,8 +604,10 @@
  * will overlap later virtual location, but as we already mapped the first
  * 16MB to 0x80000000, we can jump there after translation and MMU is enabled
  * and then we can switch off translation and go to the final place.
+ * On 020/030 we must emulate transparant translation, since 020 doesn't know
+ * it, but due to early termination pointer this is easy to do.
  * When MMU is enabled, stack pointer and Lcustom will become again valid and
- * points to the unused first page.
+ * stack points to the unused first page.
  */
 
 /*
@@ -622,15 +624,16 @@
 
 	is_040_or_060(Lamimmu68040)
 
-	lea	2f:w,%a0
+	moveq	#ROOT_INDEX_SHIFT,%d2
 	movel	%d5,%d0
-	andl	#0xff000000,%d0
-	jne	1f
-	lea	%pc@(2f+0x80000000),%a0
-1:	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+	lsrl	%d2,%d0
+	movel	%d0,%d1
+	lsll	%d2,%d1
+	addql	#_PAGE_PRESENT,%d1
+	lsll	#2,%d0
+	movel	%a5@(%d0:w),%d2
+	movel	%d1,%a5@(%d0:w)
 	lea	%pc@(Lmmu),%a3
-	movel	%d0,%a3@
-	.long	0xf0130800	/* pmove %a3@,%tt0 */
 	/* no limit, 4byte descriptors */
 	movel	#0x80000002,%a3@
 	movel	%a5,%a3@(4)
@@ -643,9 +646,12 @@
 	 */
 	movel	#0x82c07760,%a3@
 	.long	0xf0134000	/* pmove %a3@,%tc (enable the MMU) */
-	jmp	%a0@
-2:	clrl	%a3@
-	.long	0xf0130800	/* pmove %a3@,%tt0 */
+	tstl	%d0
+	jne	1f
+	jmp	%pc@(2f+0x80000000)
+1:	jmp	2f:w
+2:	movel	%d2,%a5@(%d0:w)
+	.long	0xf0002400	/* pflusha */
 	jmp	LdoneMMUenable:w
 
 Lamimmu68040:
@@ -708,7 +714,7 @@
 	 * Requires that this code until after MMU enabling lies in
 	 * the 256K page around %d5
 	 */
-2:	movel	%a4@,%d1
+2:	movel	%a5@,%d1
 	andw	#0xfff0,%d1
 	movel	%d1,%a1
 	movel	%d5,%d1
@@ -748,7 +754,8 @@
 	andl	#0xff000000,%d0 /* logical address base */
 	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
 	.long	0x4e7b0004	/* movec %d0,%itt0 */
-2:	.word	0xf518		/* pflusha */
+2:	nop
+	.word	0xf518		/* pflusha */
 	.long	0x4e7bd807	/* movec %a5,%srp */
 	.long	0x4e7bd806	/* movec %a5,%urp */
 	movel	#TC_ENABLE+TC_PAGE4K,%d0
@@ -1096,7 +1103,7 @@
 	putc('=')
 	putn(%a1)
 
-	ptestr	#5,%a1@,#7,%a0
+	.long	0xf0119f15		| ptestr	#5,%a1@,#7,%a0
 
 	putc('D')
 	putc('A')
@@ -1110,7 +1117,7 @@
 	putc('S')
 	putc('=')
 	lea	%pc@(Lmmu),%a0
-	pmove	%psr,%a0@
+	.long	0xf0106200		| pmove		%psr,%a0@
 	clrl	%d7
 	movew	%a0@,%d7
 	jbsr	Lserial_putnum
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/ints.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/kernel/ints.c	Wed Sep 25 10:47:39 1996
@@ -1,5 +1,5 @@
 /*
- * ints.c -- 680x0 Linux general interrupt handling code
+ * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
  *
  * 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
@@ -11,6 +11,18 @@
  *           remove_isr() to request_irq() and free_irq()
  *           respectively, so they are compliant with the other
  *           architectures.                                     /Jes
+ * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls.
+ *           Removed irq list support, if any machine needs an irq server
+ *           it must implement this itself (as it's already done), instead
+ *           only default handler are used with mach_default_handler.
+ *           request_irq got some flags different from other architectures:
+ *           - IRQ_FLG_REPLACE : Replace an existing handler (the default one
+ *                               can be replaced without this flag)
+ *           - IRQ_FLG_LOCK : handler can't be replaced
+ *           There are other machine depending flags, see there
+ *           If you want to replace a default handler you should know what
+ *           you're doing, since it might handle different other irq sources
+ *           which must be served                               /Roman Zippel
  */
 
 #include <linux/types.h>
@@ -24,14 +36,19 @@
 #include <asm/page.h>
 #include <asm/machdep.h>
 
-/* list is accessed 0-6 for IRQs 1-7 */
-static isr_node_t *isr_list[7];
+/* table for system interrupt handlers */
+static irq_handler_t irq_list[SYS_IRQS];
+
+static const char *default_names[SYS_IRQS] = {
+	"spurious int", "int1 handler", "int2 handler", "int3 handler",
+	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
+};
 
 /* The number of spurious interrupts */
-volatile unsigned long num_spurious;
-/*
-unsigned long interrupt_stack[PAGE_SIZE/sizeof(long)];
-*/
+volatile unsigned int num_spurious;
+
+#define NUM_IRQ_NODES 100
+static irq_node_t nodes[NUM_IRQ_NODES];
 
 /*
  * void init_IRQ(void)
@@ -46,147 +63,85 @@
 
 void init_IRQ(void)
 {
-    /* Setup interrupt stack pointer */
-  /*
-    asm ("movec %0,%/isp"
-	 : : "r" (interrupt_stack + sizeof (interrupt_stack) / sizeof (long)));
-	 */
-    mach_init_INTS ();
-}
-
-void insert_isr (isr_node_t **listp, isr_node_t *node)
-{
-    unsigned long spl;
-    isr_node_t *cur;
-
-    save_flags(spl);
-    cli();
-
-    cur = *listp;
-
-    while (cur && cur->pri <= node->pri)
-    {
-	listp = &cur->next;
-	cur = cur->next;
-    }
-
-    node->next = cur;
-    *listp = node;
-
-    restore_flags(spl);
-}
-
-void delete_isr (isr_node_t **listp, isrfunc isr, void *data)
-{
-    unsigned long flags;
-    isr_node_t *np;
+	int i;
 
-    save_flags(flags);
-    cli();
-    for (np = *listp; np; listp = &np->next, np = *listp) {
-	if (np->isr == isr && np->data == data) {
-	    *listp = np->next;
-	    /* Mark it as free. */
-	    np->isr = NULL;
-	    restore_flags(flags);
-	    return;
+	for (i = 0; i < SYS_IRQS; i++) {
+		if (mach_default_handler)
+			irq_list[i].handler = (*mach_default_handler)[i];
+		irq_list[i].flags   = IRQ_FLG_STD;
+		irq_list[i].dev_id  = NULL;
+		irq_list[i].devname = default_names[i];
 	}
-    }
-    restore_flags(flags);
-    printk ("delete_isr: isr %p not found on list!\n", isr);
-}
 
-#define NUM_ISR_NODES 100
-static isr_node_t nodes[NUM_ISR_NODES];
-
-isr_node_t *new_isr_node(void)
-{
-    isr_node_t *np;
+	for (i = 0; i < NUM_IRQ_NODES; i++)
+		nodes[i].handler = NULL;
 
-    for (np = nodes; np < &nodes[NUM_ISR_NODES]; np++)
-	if (np->isr == NULL)
-	    return np;
-
-    printk ("new_isr_node: out of nodes");
-    return NULL;
+	mach_init_IRQ ();
 }
 
-int add_isr (unsigned long source, isrfunc isr, int pri, void *data,
-	     char *name)
+irq_node_t *new_irq_node(void)
 {
-    isr_node_t *p;
-
-    if (source & IRQ_MACHSPEC)
-    {
-	return mach_add_isr (source, isr, pri, data, name);
-    }
+	irq_node_t *node;
+	short i;
 
-    if (source < IRQ1 || source > IRQ7)
-	panic ("add_isr: Incorrect IRQ source %ld from %s\n", source, name);
+	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+		if (!node->handler)
+			return node;
 
-    p = new_isr_node();
-    if (p == NULL)
-	return 0;
-    p->isr = isr;
-    p->pri = pri;
-    p->data = data;
-    p->name = name;
-    p->next = NULL;
-
-    insert_isr (&isr_list[source-1], p);
-
-    return 1;
+	printk ("new_irq_node: out of nodes\n");
+	return NULL;
 }
 
-int remove_isr (unsigned long source, isrfunc isr, void *data)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
 {
-    if (source & IRQ_MACHSPEC)
-	return mach_remove_isr (source, isr, data);
-
-    if (source < IRQ1 || source > IRQ7) {
-	printk ("remove_isr: Incorrect IRQ source %ld\n", source);
-	return 0;
-    }
+	if (irq & IRQ_MACHSPEC)
+		return mach_request_irq(IRQ_IDX(irq), handler, flags, devname, dev_id);
 
-    delete_isr (&isr_list[source - 1], isr, data);
-    return 1;
-}
+	if (irq < IRQ1 || irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
 
-void call_isr_list(int irq, isr_node_t *p, struct pt_regs *fp)
-{
-    while (p) {
-	p->isr (irq, fp, p->data);
-	p = p->next;
-    }
+	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
+		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+	}
+	irq_list[irq].handler = handler;
+	irq_list[irq].flags   = flags;
+	irq_list[irq].dev_id  = dev_id;
+	irq_list[irq].devname = devname;
+	return 0;
 }
 
-asmlinkage void process_int(int vec, struct pt_regs *regs)
+void free_irq(unsigned int irq, void *dev_id)
 {
-	int level;
-
-	if (vec >= VECOFF(VEC_INT1) && vec <= VECOFF(VEC_INT7))
-		level = (vec - VECOFF(VEC_SPUR)) >> 2;
-	else {
-		if (mach_process_int)
-			mach_process_int(vec, regs);
-		else
-			panic("Can't process interrupt vector 0x%03x\n", vec);
+	if (irq & IRQ_MACHSPEC) {
+		mach_free_irq(IRQ_IDX(irq), dev_id);
 		return;
 	}
 
-	kstat.interrupts[level]++;  	
-	call_isr_list (level, isr_list[level-1], regs);
-}
-
-int request_irq(unsigned int irq,
-		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long flags, const char * devname, void *dev_id)
-{
-	return -EINVAL;
-}
+	if (irq < IRQ1 || irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
 
-void free_irq(unsigned int irq, void *dev_id)
-{
+	if (irq_list[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_list[irq].devname);
+
+	irq_list[irq].handler = (*mach_default_handler)[irq];
+	irq_list[irq].flags   = IRQ_FLG_STD;
+	irq_list[irq].dev_id  = NULL;
+	irq_list[irq].devname = default_names[irq];
 }
 
 /*
@@ -194,43 +149,58 @@
  */
 unsigned long probe_irq_on (void)
 {
-  return 0;
+	return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-  return 0;
+	return 0;
 }
 
-void enable_irq(unsigned int irq_nr)
+void enable_irq(unsigned int irq)
 {
-	if ((irq_nr & IRQ_MACHSPEC) && mach_enable_irq)
-		mach_enable_irq(irq_nr);
+	if ((irq & IRQ_MACHSPEC) && mach_enable_irq)
+		mach_enable_irq(IRQ_IDX(irq));
 }
 
-void disable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq)
 {
-	if ((irq_nr & IRQ_MACHSPEC) && mach_disable_irq)
-		mach_disable_irq(irq_nr);
+	if ((irq & IRQ_MACHSPEC) && mach_disable_irq)
+		mach_disable_irq(IRQ_IDX(irq));
+}
+
+asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
+{
+	if (vec < VEC_INT1 || vec > VEC_INT7) {
+		if (mach_process_int)
+			mach_process_int(vec, fp);
+		else
+			panic("Can't process interrupt vector %ld\n", vec);
+		return;
+	}
+
+	vec -= VEC_SPUR;
+	kstat.interrupts[vec]++;
+	irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
 }
 
 int get_irq_list(char *buf)
 {
-    int i, len = 0;
-    isr_node_t *p;
-    
-    /* autovector interrupts */
-    for (i = IRQ1; i <= IRQ7; ++i) {
-	if (!isr_list[i-1])
-	    continue;
-	len += sprintf(buf+len, "auto %2d: %8d ", i, kstat.interrupts[i]);
-	for (p = isr_list[i-1]; p; p = p->next) {
-	    len += sprintf(buf+len, "%s\n", p->name);
-	    if (p->next)
-		len += sprintf(buf+len, "                  ");
+	int i, len = 0;
+
+	/* autovector interrupts */
+	if (mach_default_handler) {
+		for (i = 0; i < SYS_IRQS; i++) {
+			len += sprintf(buf+len, "auto %2d: %10u ", i,
+			               i ? kstat.interrupts[i] : num_spurious);
+			if (irq_list[i].flags & IRQ_FLG_LOCK)
+				len += sprintf(buf+len, "L ");
+			else
+				len += sprintf(buf+len, "  ");
+			len += sprintf(buf+len, "%s\n", irq_list[i].devname);
+		}
 	}
-    }
 
-    len = mach_get_irq_list(buf, len);
-    return len;
+	len += mach_get_irq_list(buf+len);
+	return len;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/ksyms.c linux/arch/m68k/kernel/ksyms.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/ksyms.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/kernel/ksyms.c	Wed Sep 25 10:47:39 1996
@@ -1,14 +1,16 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/linkage.h>
+#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/user.h>
 #include <linux/elfcore.h>
 
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
+#include <asm/semaphore.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 extern char m68k_debug_device[];
@@ -34,14 +36,16 @@
 	X(boot_info),
 	X(m68k_is040or060),
 	X(cache_push),
+	X(cache_push_v),
 	X(cache_clear),
 	X(mm_vtop),
 	X(mm_ptov),
 	X(m68k_debug_device),
-	X(add_isr),
-	X(remove_isr),
+	X(request_irq),
+	X(free_irq),
 	X(dump_fpu),
 	X(dump_thread),
+	X(strnlen),
 
 	/* The following are special because they're not called
 	   explicitly (the C compiler generates them).  Fortunately,
@@ -49,7 +53,11 @@
 	   it's OK to leave it out of version control.  */
 	XNOVERS(__ashrdi3),
 	XNOVERS(memcpy),
-	
+	XNOVERS(memset),
+
+	XNOVERS(down_failed),
+	XNOVERS(up_wakeup),
+
 #include <linux/symtab_end.h>
 };
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/process.c	Mon Apr  1 21:40:27 1996
+++ linux/arch/m68k/kernel/process.c	Wed Sep 25 10:47:39 1996
@@ -2,6 +2,8 @@
  *  linux/arch/m68k/kernel/process.c
  *
  *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  68060 fixes by Jesper Skov
  */
 
 /*
@@ -23,6 +25,7 @@
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
+#include <asm/setup.h>
 
 asmlinkage void ret_from_exception(void);
 
@@ -125,10 +128,17 @@
 
 	p->tss.usp = usp;
 	p->tss.ksp = (unsigned long)childstack;
+	/*
+	 * Must save the current SFC/DFC value, NOT the value when
+	 * the parent was last descheduled - RGH  10-08-96
+	 */
+	p->tss.fs = get_fs();
 
 	/* Copy the current fpu state */
 	asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
-	if (p->tss.fpstate[0])
+
+	if((!CPU_IS_060 && p->tss.fpstate[0]) ||
+	   (CPU_IS_060 && p->tss.fpstate[2]))
 	  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
 			"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
 			: : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
@@ -145,8 +155,8 @@
 
   /* First dump the fpu context to avoid protocol violation.  */
   asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-  if (!fpustate[0])
-    return 0;
+  if((!CPU_IS_060 && !fpustate[0]) || (CPU_IS_060 && !fpustate[2]))
+     return 0;
 
   asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
 		:: "m" (fpu->fpcntl[0])
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/ptrace.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/kernel/ptrace.c	Wed Sep 25 10:47:39 1996
@@ -198,6 +198,7 @@
 /* this is a hack for non-kernel-mapped video buffers and similar */
 	if (page < high_memory) {
 		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+		flush_page_to_ram (page);
 	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
@@ -210,7 +211,7 @@
 	struct vm_area_struct * vma;
 
 	addr &= PAGE_MASK;
-	vma = find_vma(tsk,addr);
+	vma = find_vma(tsk->mm, addr);
 	if (!vma)
 		return NULL;
 	if (vma->vm_start <= addr)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/setup.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/kernel/setup.c	Wed Sep 25 10:47:39 1996
@@ -19,7 +19,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 
-#include <asm/bootinfo.h>
+#include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/machdep.h>
 #include <asm/amigatypes.h>
@@ -47,17 +47,22 @@
 {
 }
 
-void (*mach_sched_init) (isrfunc);
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
+/* machine dependent keyboard functions */
 int (*mach_keyb_init) (void);
 int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
 void (*mach_kbd_leds) (unsigned int) = NULL;
-void (*mach_init_INTS) (void);
-int (*mach_add_isr) (unsigned long, isrfunc, int, void *, char *);
-int (*mach_remove_isr) (unsigned long, isrfunc, void *);
+/* machine dependent irq functions */
+void (*mach_init_IRQ) (void);
+void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
+int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *),
+                         unsigned long, const char *, void *);
+int (*mach_free_irq) (unsigned int, void *);
+void (*mach_enable_irq) (unsigned int) = NULL;
+void (*mach_disable_irq) (unsigned int) = NULL;
+int (*mach_get_irq_list) (char *) = NULL;
 void (*mach_process_int) (int, struct pt_regs *) = NULL;
-void (*mach_enable_irq) (unsigned) = NULL;
-void (*mach_disable_irq) (unsigned) = NULL;
-int (*mach_get_irq_list) (char *, int) = NULL;
+/* machine dependent timer functions */
 unsigned long (*mach_gettimeoffset) (void);
 void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
 int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
@@ -78,6 +83,7 @@
 extern void config_amiga(void);
 extern void config_atari(void);
 extern void config_mac(void);
+extern void config_sun3(void);
 
 extern void register_console(void (*proc)(const char *));
 extern void ami_serial_print (const char *str);
@@ -102,18 +108,15 @@
 	int i;
 	char *p, *q;
 
-#ifdef CONFIG_AMIGA
 	if (MACH_IS_AMIGA)
-	  register_console (ami_serial_print);
-#endif
-#ifdef CONFIG_ATARI
+		register_console(ami_serial_print);
+
 	if (MACH_IS_ATARI)
-	  register_console (ata_serial_print);
-#endif
+		register_console(ata_serial_print);
 
-	if (boot_info.cputype & CPU_68040)
+	if (CPU_IS_040)
 		m68k_is040or060 = 4;
-	else if (boot_info.cputype & CPU_68060)
+	else if (CPU_IS_060)
 		m68k_is040or060 = 6;
 
 	/* clear the fpu if we have one */
@@ -179,6 +182,11 @@
 		config_mac();
 		break;
 #endif
+#ifdef CONFIG_SUN3
+	    case MACH_SUN3:
+	    	config_sun3();
+	    	break;
+#endif
 	    default:
 		panic ("No configuration setup");
 	}
@@ -191,39 +199,29 @@
 #endif
 }
 
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	return -EOPNOTSUPP;
-}
-
-int getkeycode(unsigned int scancode)
-{
-	return -EOPNOTSUPP;
-}
-
 int get_cpuinfo(char * buffer)
 {
     char *cpu, *mmu, *fpu;
     u_long clockfreq, clockfactor;
 
-#define CLOCK_FACTOR_68020	(8046)	/*  3107016 loops/s @ 25 MHz (Sun-3) */
-#define CLOCK_FACTOR_68030	(8010)	/*  3994575 loops/s @ 32 MHz */
-#define CLOCK_FACTOR_68040	(3010)	/*  8305552 loops/s @ 25 MHz */
-#define CLOCK_FACTOR_68060	(998)	/* 50081241 loops/s @ 50 MHz */
+#define LOOP_CYCLES_68020	(8)
+#define LOOP_CYCLES_68030	(8)
+#define LOOP_CYCLES_68040	(3)
+#define LOOP_CYCLES_68060	(1)
 
-    if (boot_info.cputype & CPU_68020) {
+    if (CPU_IS_020) {
 	cpu = "68020";
 	mmu = "68851";
-	clockfactor = CLOCK_FACTOR_68020;
-    } else if (boot_info.cputype & CPU_68030) {
+	clockfactor = LOOP_CYCLES_68020;
+    } else if (CPU_IS_030) {
 	cpu = mmu = "68030";
-	clockfactor = CLOCK_FACTOR_68030;
-    } else if (boot_info.cputype & CPU_68040) {
+	clockfactor = LOOP_CYCLES_68030;
+    } else if (CPU_IS_040) {
 	cpu = mmu = "68040";
-	clockfactor = CLOCK_FACTOR_68040;
-    } else if (boot_info.cputype & CPU_68060) {
+	clockfactor = LOOP_CYCLES_68040;
+    } else if (CPU_IS_060) {
 	cpu = mmu = "68060";
-	clockfactor = CLOCK_FACTOR_68060;
+	clockfactor = LOOP_CYCLES_68060;
     } else {
 	cpu = mmu = "680x0";
 	clockfactor = 0;
@@ -240,16 +238,19 @@
     else
 	fpu = "none";
 
-    clockfreq = loops_per_sec/1000*clockfactor;
+    clockfreq = loops_per_sec*clockfactor;
 
     return(sprintf(buffer, "CPU:\t\t%s\n"
 		   "MMU:\t\t%s\n"
 		   "FPU:\t\t%s\n"
-		   "Clockspeed:\t%lu.%1luMHz\n"
-		   "BogoMips:\t%lu.%02lu\n",
-		   cpu, mmu, fpu, (clockfreq+50000)/1000000,
-		   ((clockfreq+50000)/100000)%10, loops_per_sec/500000,
-		   (loops_per_sec/5000)%100));
+		   "Clocking:\t%lu.%1luMHz\n"
+		   "BogoMips:\t%lu.%02lu\n"
+		   "Calibration:\t%lu loops\n",
+		   cpu, mmu, fpu,
+		   clockfreq/1000000,(clockfreq/100000)%10,
+		   loops_per_sec/500000,(loops_per_sec/5000)%100,
+		   loops_per_sec));
+
 }
 
 int get_hardware_list(char *buffer)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/signal.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/kernel/signal.c	Wed Sep 25 10:47:39 1996
@@ -9,7 +9,17 @@
  */
 
 /*
- * 680x0 support by Hamish Macdonald
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ */
+
+/*
+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
+ * If a second signal with SA_STACK set arrives while working on a sigstack,
+ * SA_STACK is ignored. This behaviour avoids lots of trouble with nested
+ * signal handlers!
  */
 
 #include <linux/sched.h>
@@ -21,10 +31,10 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/traps.h>
-#include <asm/bootinfo.h>
 
 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
 
@@ -74,13 +84,10 @@
 
 static unsigned char fpu_version = 0;	/* version number of fpu, set by setup_frame */
 
-/*
- * This sets regs->usp even though we don't actually use sigstacks yet..
- */
 asmlinkage int do_sigreturn(unsigned long __unused)
 {
 	struct sigcontext_struct context;
-	struct frame * regs;
+	struct pt_regs *regs;
 	struct switch_stack *sw;
 	int fsize = 0;
 	int formatvec = 0;
@@ -93,7 +100,7 @@
 
 	/* get stack frame pointer */
 	sw = (struct switch_stack *) &__unused;
-	regs = (struct frame *) (sw + 1);
+	regs = (struct pt_regs *) (sw + 1);
 
 	/* get previous context (including pointer to possible extra junk) */
         if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
@@ -107,37 +114,21 @@
 	current->blocked = context.sc_mask & _BLOCKABLE;
 
 	/* restore passed registers */
-	regs->ptregs.d0 = context.sc_d0;
-	regs->ptregs.d1 = context.sc_d1;
-	regs->ptregs.a0 = context.sc_a0;
-	regs->ptregs.a1 = context.sc_a1;
-	regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff);
-	regs->ptregs.pc = context.sc_pc;
-
+	regs->d0 = context.sc_d0;
+	regs->d1 = context.sc_d1;
+	regs->a0 = context.sc_a0;
+	regs->a1 = context.sc_a1;
+	regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
+	regs->pc = context.sc_pc;
+	regs->orig_d0 = -1;		/* disable syscall checks */
 	wrusp(context.sc_usp);
 	formatvec = context.sc_formatvec;
-	regs->ptregs.format = formatvec >> 12;
-	regs->ptregs.vector = formatvec & 0xfff;
-	if (context.sc_fpstate[0])
-	  {
+	regs->format = formatvec >> 12;
+	regs->vector = formatvec & 0xfff;
+	if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
 	    /* Verify the frame format.  */
-	    if (context.sc_fpstate[0] != fpu_version){
-#if DEBUG
-	    printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
-		   context.sc_fpcntl); 
-	    printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n",
-		   (unsigned) context.sc_fpstate[0], (unsigned) fpu_version);
-	    {
-	      int i;
-	      printk("Saved fp_state: ");
-	      for (i = 0; i < 216; i++){
-		printk("%02x ", context.sc_fpstate[i]);
-	      }
-	      printk("\n");
-	    }
-#endif
+	    if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version))
 	      goto badframe;
-	    }
 	    if (boot_info.cputype & FPU_68881)
 	      {
 		if (context.sc_fpstate[1] != 0x18
@@ -147,34 +138,22 @@
 	    else if (boot_info.cputype & FPU_68882)
 	      {
 		if (context.sc_fpstate[1] != 0x38
-		    && context.sc_fpstate[1] != 0xd4){
-#if 0
-		  printk("Wrong 68882 fpu-state\n");
-#endif
+		    && context.sc_fpstate[1] != 0xd4)
 		  goto badframe;
-		}
 	      }
 	    else if (boot_info.cputype & FPU_68040)
 	      {
-		if (!((context.sc_fpstate[1] == 0x00)|| \
-                      (context.sc_fpstate[1] == 0x28)|| \
-                      (context.sc_fpstate[1] == 0x60))){
-#if 0
-		  printk("Wrong 68040 fpu-state\n");
-#endif
+		if (!(context.sc_fpstate[1] == 0x00 ||
+                      context.sc_fpstate[1] == 0x28 ||
+                      context.sc_fpstate[1] == 0x60))
 		  goto badframe;
-		}
 	      }
 	    else if (boot_info.cputype & FPU_68060)
 	      {
-		if (!((context.sc_fpstate[1] == 0x00)|| \
-                      (context.sc_fpstate[1] == 0x60)|| \
-                      (context.sc_fpstate[1] == 0xe0))){
-#if 0
-		  printk("Wrong 68060 fpu-state\n");
-#endif
+		if (!(context.sc_fpstate[3] == 0x00 ||
+                      context.sc_fpstate[3] == 0x60 ||
+		      context.sc_fpstate[3] == 0xe0))
 		  goto badframe;
-		}
 	      }
 	    __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
 			      "fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
@@ -184,17 +163,20 @@
 	  }
 	__asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
 
-	fsize = extra_sizes[regs->ptregs.format];
+	fsize = extra_sizes[regs->format];
 	if (fsize < 0) {
 		/*
 		 * user process trying to return with weird frame format
 		 */
 #if DEBUG
-	      printk("user process returning with weird frame format\n");
+		printk("user process returning with weird frame format\n");
 #endif
 		goto badframe;
 	}
 
+	if (context.sc_usp != fp+fsize)
+		current->flags &= ~PF_ONSIGSTK;
+	
 	/* OK.	Make room on the supervisor stack for the extra junk,
 	 * if necessary.
 	 */
@@ -227,7 +209,7 @@
 		/* NOTREACHED */
 	}
 
-	return regs->ptregs.d0;
+	return regs->d0;
 badframe:
         do_exit(SIGSEGV);
 }
@@ -275,25 +257,31 @@
 
 #define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
 
-static void setup_frame (struct sigaction * sa, unsigned long **fp,
-			 unsigned long pc, struct frame *regs, int
-			 signr, unsigned long oldmask)
+static void setup_frame (struct sigaction * sa, struct pt_regs *regs,
+			 int signr, unsigned long oldmask)
 {
 	struct sigcontext_struct context;
 	unsigned long *frame, *tframe;
-	int fsize = extra_sizes[regs->ptregs.format];
+	int fsize = extra_sizes[regs->format];
 
 	if (fsize < 0) {
 		printk ("setup_frame: Unknown frame format %#x\n",
-			regs->ptregs.format);
+			regs->format);
 		do_exit(SIGSEGV);
 	}
-	frame = *fp - UFRAME_SIZE(fsize);
+
+	frame = (unsigned long *)rdusp();
+	if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) {
+		frame = (unsigned long *)sa->sa_restorer;
+		current->flags |= PF_ONSIGSTK;
+	}
+	frame -= UFRAME_SIZE(fsize);
+
 	if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
 		do_exit(SIGSEGV);
 	if (fsize) {
-		memcpy_tofs (frame + UFRAME_SIZE(0), &regs->un, fsize);
-		regs->ptregs.stkadj = fsize;
+		memcpy_tofs (frame + UFRAME_SIZE(0), regs + 1, fsize);
+		regs->stkadj = fsize;
 	}
 
 /* set up the "normal" stack seen by the signal handler */
@@ -307,7 +295,7 @@
 	    put_user(signr, tframe);
 	tframe++;
 
-	put_user(regs->ptregs.vector, tframe); tframe++;
+	put_user(regs->vector, tframe); tframe++;
 	/* "scp" parameter.  points to sigcontext */
 	put_user((ulong)(frame+6), tframe); tframe++;
 
@@ -320,60 +308,85 @@
 
 /* setup and copy the sigcontext structure */
 	context.sc_mask       = oldmask;
-	context.sc_usp	      = (unsigned long)*fp;
-	context.sc_d0	      = regs->ptregs.d0;
-	context.sc_d1	      = regs->ptregs.d1;
-	context.sc_a0	      = regs->ptregs.a0;
-	context.sc_a1	      = regs->ptregs.a1;
-	context.sc_sr	      = regs->ptregs.sr;
-	context.sc_pc	      = pc;
-	context.sc_formatvec  = (regs->ptregs.format << 12 |
-				 regs->ptregs.vector);
-#if DEBUG
-	printk("formatvec: %02x\n", (unsigned) context.sc_formatvec);
-#endif
+	context.sc_usp	      = rdusp();
+	context.sc_d0	      = regs->d0;
+	context.sc_d1	      = regs->d1;
+	context.sc_a0	      = regs->a0;
+	context.sc_a1	      = regs->a1;
+	context.sc_sr	      = regs->sr;
+	context.sc_pc	      = regs->pc;
+	context.sc_formatvec  = (regs->format << 12 | regs->vector);
 	__asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
-	if (context.sc_fpstate[0])
-	  {
-	    fpu_version = context.sc_fpstate[0];
-#if DEBUG
-	    {
-	      int i;
-	      printk("Saved fp_state: ");
-	      for (i = 0; i < 216; i++){
-		printk("%02x ", context.sc_fpstate[i]);
-	      }
-	      printk("\n");
-	    }
-	    printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
-		   context.sc_fpcntl); 
-#endif
-	    __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
-			      "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
-			      : /* no outputs */
-			      : "m" (*context.sc_fpregs),
-				"m" (*context.sc_fpcntl)
-			      : "memory");
-	  }
-#if DEBUG
-	{
-	  int i;
-	  printk("Saved fp_state: ");
-	  for (i = 0; i < 216; i++){
-	    printk("%02x ", context.sc_fpstate[i]);
-	  }
-	  printk("\n");
+	if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
+		fpu_version = context.sc_fpstate[0];
+		__asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
+				  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
+				  : /* no outputs */
+				  : "m" (*context.sc_fpregs),
+				  "m" (*context.sc_fpcntl)
+				  : "memory");
 	}
-#endif
 	memcpy_tofs (tframe, &context, sizeof(context));
+
 	/*
 	 * no matter what frame format we were using before, we
 	 * will do the "RTE" using a normal 4 word frame.
 	 */
-	regs->ptregs.format = 0;
+	regs->format = 0;
+
+	/* Set up registers for signal handler */
+	wrusp ((unsigned long) frame);
+	regs->pc = (unsigned long) sa->sa_handler;
+
+	/* Prepare to skip over the extra stuff in the exception frame.  */
+	if (regs->stkadj) {
+		struct pt_regs *tregs =
+			(struct pt_regs *)((ulong)regs + regs->stkadj);
+#if DEBUG
+		printk("Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+		/* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+		tregs->vector = regs->vector;
+		tregs->format = regs->format;
+		tregs->pc = regs->pc;
+		tregs->sr = regs->sr;
+	}
+}
 
-	/* "return" new usp to caller */
-	*fp = frame;
+/*
+ * OK, we're invoking a handler
+ */	
+static void handle_signal(unsigned long signr, struct sigaction *sa,
+			  unsigned long oldmask, struct pt_regs *regs)
+{
+	/* are we from a system call? */
+	if (regs->orig_d0 >= 0) {
+		/* If so, check system call restarting.. */
+		switch (regs->d0) {
+			case -ERESTARTNOHAND:
+				regs->d0 = -EINTR;
+				break;
+
+			case -ERESTARTSYS:
+				if (!(sa->sa_flags & SA_RESTART)) {
+					regs->d0 = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				regs->d0 = regs->orig_d0;
+				regs->pc -= 2;
+		}
+	}
+
+	/* set up the stack frame */
+	setup_frame(sa, regs, signr, oldmask);
+
+	if (sa->sa_flags & SA_ONESHOT)
+		sa->sa_handler = NULL;
+	if (!(sa->sa_flags & SA_NOMASK))
+		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
 }
 
 /*
@@ -385,52 +398,59 @@
  * that the kernel can handle, and then we build all the user-level signal
  * handling stack-frames in one go after that.
  */
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
 {
 	unsigned long mask = ~current->blocked;
-	unsigned long handler_signal = 0;
-	unsigned long *frame = NULL;
-	unsigned long pc = 0;
 	unsigned long signr;
-	struct frame *regs = (struct frame *)regs_in;
 	struct sigaction * sa;
 
 	current->tss.esp0 = (unsigned long) regs;
 
+	/* If the process is traced, all signals are passed to the debugger. */
+	if (current->flags & PF_PTRACED)
+		mask = ~0UL;
 	while ((signr = current->signal & mask)) {
 		__asm__("bfffo  %2,#0,#0,%1\n\t"
 			"bfclr  %0,%1,#1\n\t"
 			"eorw   #31,%1"
-			:"=m" (current->signal),"=r" (signr)
-			:"1" (signr));
+			:"=m" (current->signal),"=d" (signr)
+			:"0" (current->signal), "1" (signr));
 		sa = current->sig->action + signr;
 		signr++;
 
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
+
+			/* Did we come from a system call? */
+			if (regs->orig_d0 >= 0) {
+				/* Restart the system call */
+				if (regs->d0 == -ERESTARTNOHAND ||
+				    regs->d0 == -ERESTARTSYS ||
+				    regs->d0 == -ERESTARTNOINTR) {
+					regs->d0 = regs->orig_d0;
+					regs->pc -= 2;
+				}
+			}
 			notify_parent(current);
 			schedule();
 			if (!(signr = current->exit_code)) {
 			discard_frame:
-				/* Make sure that a faulted bus cycle
-				   isn't restarted.  */
-				switch (regs->ptregs.format) {
-				case 7:
-				case 9:
-				case 10:
-				case 11:
-				  regs->ptregs.stkadj = extra_sizes[regs->ptregs.format];
-				  regs->ptregs.format = 0;
-				  break;
-				}
-				continue;
+			    /* Make sure that a faulted bus cycle
+			       isn't restarted (only needed on the
+			       68030).  */
+			    if (regs->format == 10 || regs->format == 11) {
+				regs->stkadj = extra_sizes[regs->format];
+				regs->format = 0;
+			    }
+			    continue;
 			}
 			current->exit_code = 0;
 			if (signr == SIGSTOP)
 				goto discard_frame;
 			if (_S(signr) & current->blocked) {
 				current->signal |= _S(signr);
+				mask &= ~_S(signr);
 				continue;
 			}
 			sa = current->sig->action + signr - 1;
@@ -447,10 +467,13 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			    case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
-			    case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+			case SIGSTOP:
 				if (current->flags & PF_PTRACED)
 					continue;
 				current->state = TASK_STOPPED;
@@ -461,97 +484,46 @@
 				schedule();
 				continue;
 
-			    case SIGQUIT: case SIGILL: case SIGTRAP:
-			    case SIGIOT: case SIGFPE: case SIGSEGV:
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGIOT: case SIGFPE: case SIGSEGV:
 				if (current->binfmt && current->binfmt->core_dump) {
-				    if (current->binfmt->core_dump(signr, (struct pt_regs *)regs))
+				    if (current->binfmt->core_dump(signr, regs))
 					signr |= 0x80;
 				}
 				/* fall through */
-			    default:
+			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
-		/*
-		 * OK, we're invoking a handler
-		 */
-		if (regs->ptregs.orig_d0 >= 0) {
-		  if (regs->ptregs.d0 == -ERESTARTNOHAND ||
-		      (regs->ptregs.d0 == -ERESTARTSYS &&
-		       !(sa->sa_flags & SA_RESTART)))
-		    regs->ptregs.d0 = -EINTR;
-		}
-		handler_signal |= 1 << (signr-1);
-		mask &= ~sa->sa_mask;
+		handle_signal(signr, sa, oldmask, regs);
+		return 1;
 	}
-	if (regs->ptregs.orig_d0 >= 0 &&
-	    (regs->ptregs.d0 == -ERESTARTNOHAND ||
-	     regs->ptregs.d0 == -ERESTARTSYS ||
-	     regs->ptregs.d0 == -ERESTARTNOINTR)) {
-		regs->ptregs.d0 = regs->ptregs.orig_d0;
-		regs->ptregs.pc -= 2;
-	}
-	if (!handler_signal)    /* no handler will be called - return 0 */
-	  {
-	    /* If we are about to discard some frame stuff we must
-	       copy over the remaining frame. */
-	    if (regs->ptregs.stkadj)
-	      {
-		struct frame *tregs =
-		  (struct frame *) ((ulong) regs + regs->ptregs.stkadj);
 
-		/* This must be copied with decreasing addresses to
-		   handle overlaps.  */
-		tregs->ptregs.vector = regs->ptregs.vector;
-		tregs->ptregs.format = regs->ptregs.format;
-		tregs->ptregs.pc = regs->ptregs.pc;
-		tregs->ptregs.sr = regs->ptregs.sr;
-	      }
-	    return 0;
-	  }
-	pc = regs->ptregs.pc;
-	frame = (unsigned long *)rdusp();
-	signr = 1;
-	sa = current->sig->action;
-	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
-		if (mask > handler_signal)
-			break;
-		if (!(mask & handler_signal))
-			continue;
-		setup_frame(sa,&frame,pc,regs,signr,oldmask);
-		pc = (unsigned long) sa->sa_handler;
-		if (sa->sa_flags & SA_ONESHOT)
-			sa->sa_handler = NULL;
-/* force a supervisor-mode page-in of the signal handler to reduce races */
-		__asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0");
-		current->blocked |= sa->sa_mask;
-		oldmask |= sa->sa_mask;
+	/* Did we come from a system call? */
+	if (regs->orig_d0 >= 0) {
+		/* Restart the system call - no handlers present */
+		if (regs->d0 == -ERESTARTNOHAND ||
+		    regs->d0 == -ERESTARTSYS ||
+		    regs->d0 == -ERESTARTNOINTR) {
+			regs->d0 = regs->orig_d0;
+			regs->pc -= 2;
+		}
 	}
-	wrusp((unsigned long)frame);
-	regs->ptregs.pc = pc;
 
-	/*
-	 * if setup_frame saved some extra frame junk, we need to
-	 * skip over that stuff when doing the RTE.  This means we have
-	 * to move the machine portion of the stack frame to where the
-	 * "RTE" instruction expects it. The signal that we need to
-	 * do this is that regs->stkadj is nonzero.
-	 */
-	if (regs->ptregs.stkadj) {
-		struct frame *tregs =
-			(struct frame *)((ulong)regs + regs->ptregs.stkadj);
-#if DEBUG
-	  printk("Performing stackadjust=%04x\n", (unsigned)
-		 regs->ptregs.stkadj);
-#endif
+	/* If we are about to discard some frame stuff we must copy
+	   over the remaining frame. */
+	if (regs->stkadj) {
+		struct pt_regs *tregs =
+		  (struct pt_regs *) ((ulong) regs + regs->stkadj);
+
 		/* This must be copied with decreasing addresses to
-                   handle overlaps.  */
-		tregs->ptregs.vector = regs->ptregs.vector;
-		tregs->ptregs.format = regs->ptregs.format;
-		tregs->ptregs.pc = regs->ptregs.pc;
-		tregs->ptregs.sr = regs->ptregs.sr;
+		   handle overlaps.  */
+		tregs->vector = regs->vector;
+		tregs->format = regs->format;
+		tregs->pc = regs->pc;
+		tregs->sr = regs->sr;
 	}
-
-	return 1;
+	return 0;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/sys_m68k.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/kernel/sys_m68k.c	Wed Sep 25 10:47:39 1996
@@ -6,7 +6,6 @@
  * platform.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -16,8 +15,10 @@
 #include <linux/stat.h>
 #include <linux/mman.h>
 
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/cachectl.h>
+#include <asm/traps.h>
 
 /*
  * sys_pipe() is the normal C calling standard for creating
@@ -198,12 +199,12 @@
 			: "=d" (_tmp2)					\
 			: "a" (_tmp1));					\
   _mmusr = _tmp2;							\
-  if (0 /* XXX _mmusr & MMU_?_040 */)					\
+  if (!(_mmusr & MMU_R_040))						\
     (valid) = 0;							\
   else									\
     {									\
       (valid) = 1;							\
-      (paddr) = _mmusr & ~0xfff;					\
+      (paddr) = _mmusr & PAGE_MASK;					\
     }									\
 }
 
@@ -237,6 +238,8 @@
 
     case FLUSH_SCOPE_LINE:
       len >>= 4;
+      /* Find the physical address of the first mapped page in the
+	 address range.  */
       for (;;)
 	{
 	  virt_to_phys_040 (addr, paddr, valid);
@@ -244,8 +247,8 @@
 	    break;
 	  if (len <= PAGE_SIZE / 16)
 	    return 0;
-	  len -= PAGE_SIZE / 16;
-	  addr += PAGE_SIZE;
+	  len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
+	  addr = (addr + PAGE_SIZE) & PAGE_MASK;
 	}
       while (len--)
 	{
@@ -283,8 +286,8 @@
 			break;
 		      if (len <= PAGE_SIZE / 16)
 			return 0;
-		      len -= PAGE_SIZE / 16;
-		      addr += PAGE_SIZE;
+		      len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
+		      addr = (addr + PAGE_SIZE) & PAGE_MASK;
 		    }
 		}
 	      else
@@ -367,6 +370,8 @@
 
     case FLUSH_SCOPE_LINE:
       len >>= 4;
+      /* Find the physical address of the first mapped page in the
+	 address range.  */
       for (;;)
 	{
 	  virt_to_phys_060 (addr, paddr, valid);
@@ -374,8 +379,8 @@
 	    break;
 	  if (len <= PAGE_SIZE / 16)
 	    return 0;
-	  len -= PAGE_SIZE / 16;
-	  addr += PAGE_SIZE;
+	  len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
+	  addr = (addr + PAGE_SIZE) & PAGE_MASK;
 	}
       while (len--)
 	{
@@ -413,8 +418,8 @@
 			break;
 		      if (len <= PAGE_SIZE / 16)
 			return 0;
-		      len -= PAGE_SIZE / 16;
-		      addr += PAGE_SIZE;
+		      len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
+		      addr = (addr + PAGE_SIZE) & PAGE_MASK;
 		    }
 		}
 	      else
@@ -477,17 +482,15 @@
     {
       /* Verify that the specified address region actually belongs to
 	 this process.  */
-      vma = find_vma (current, addr);
+      vma = find_vma (current->mm, addr);
       if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
 	return -EINVAL;
     }
 
-  switch (m68k_is040or060)
-    {
-    default: /* 030 */
-      /* Always flush the whole cache, everything else would not be
-	 worth the hassle.  */
-      __asm__ __volatile__
+  if (CPU_IS_020_OR_030) {
+    /* Always flush the whole cache, everything else would not be
+       worth the hassle.  */
+    __asm__ __volatile__
 	("movec %%cacr, %%d0\n\t"
 	 "or %0, %%d0\n\t"
 	 "movec %%d0, %%cacr"
@@ -495,12 +498,9 @@
 	 : "di" ((cache & FLUSH_CACHE_INSN ? 8 : 0)
 		 | (cache & FLUSH_CACHE_DATA ? 0x800 : 0))
 	 : "d0");
-      return 0;
-
-    case 4: /* 040 */
-      return cache_flush_040 (addr, scope, cache, len);
-
-    case 6: /* 060 */
-      return cache_flush_060 (addr, scope, cache, len);
-    }
+    return 0;
+  } else if (CPU_IS_040)
+    return cache_flush_040 (addr, scope, cache, len);
+  else if (CPU_IS_060)
+    return cache_flush_060 (addr, scope, cache, len);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/time.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/kernel/time.c	Wed Sep 25 10:47:40 1996
@@ -32,7 +32,7 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static void timer_interrupt(int irq, struct pt_regs * regs, void *dummy)
+static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- lx2.0/v2.0.21/linux/arch/m68k/kernel/traps.c	Mon May 20 07:54:26 1996
+++ linux/arch/m68k/kernel/traps.c	Wed Sep 25 10:47:40 1996
@@ -28,10 +28,10 @@
 #include <linux/string.h>
 #include <linux/linkage.h>
 
+#include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/traps.h>
-#include <asm/bootinfo.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 
@@ -77,8 +77,7 @@
                 vectors[VEC_INT7] = nmihandler;
         }
 
-#ifdef CONFIG_FPSP_040
-	if (m68k_is040or060 == 4) {
+	if (CPU_IS_040) {
 		/* set up FPSP entry points */
 		asmlinkage void dz_vec(void) asm ("dz");
 		asmlinkage void inex_vec(void) asm ("inex");
@@ -101,38 +100,34 @@
 		vectors[VEC_LINE11] = fline_vec;
 		vectors[VEC_FPUNSUP] = unsupp_vec;
 	}
-#endif
-#ifdef CONFIG_IFPSP_060
-	if (m68k_is040or060 == 6) {
-	  /* set up IFPSP entry points */
- 	  asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
- 	  asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
- 	  asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl");
- 	  asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl");
- 	  asmlinkage void dz_vec(void) asm ("_060_fpsp_dz");
- 	  asmlinkage void inex_vec(void) asm ("_060_fpsp_inex");
- 	  asmlinkage void fline_vec(void) asm ("_060_fpsp_fline");
- 	  asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
- 	  asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
-  
- 	  asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
-  
- 	  vectors[VEC_FPNAN] = snan_vec;
- 	  vectors[VEC_FPOE] = operr_vec;
- 	  vectors[VEC_FPOVER] = ovfl_vec;
- 	  vectors[VEC_FPUNDER] = unfl_vec;
- 	  vectors[VEC_FPDIVZ] = dz_vec;
- 	  vectors[VEC_FPIR] = inex_vec;
- 	  vectors[VEC_LINE11] = fline_vec;
- 	  vectors[VEC_FPUNSUP] = unsupp_vec;
- 	  vectors[VEC_UNIMPEA] = effadd_vec;
-  
- 	  /* set up ISP entry points */
-  
- 	  vectors[VEC_UNIMPII] = unimp_vec;
-  
-  	}
-#endif
+	if (CPU_IS_060) {
+		/* set up IFPSP entry points */
+		asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
+		asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
+		asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl");
+		asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl");
+		asmlinkage void dz_vec(void) asm ("_060_fpsp_dz");
+		asmlinkage void inex_vec(void) asm ("_060_fpsp_inex");
+		asmlinkage void fline_vec(void) asm ("_060_fpsp_fline");
+		asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
+		asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
+
+		asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
+
+		vectors[VEC_FPNAN] = snan_vec;
+		vectors[VEC_FPOE] = operr_vec;
+		vectors[VEC_FPOVER] = ovfl_vec;
+		vectors[VEC_FPUNDER] = unfl_vec;
+		vectors[VEC_FPDIVZ] = dz_vec;
+		vectors[VEC_FPIR] = inex_vec;
+		vectors[VEC_LINE11] = fline_vec;
+		vectors[VEC_FPUNSUP] = unsupp_vec;
+		vectors[VEC_UNIMPEA] = effadd_vec;
+
+		/* set up ISP entry points */
+
+		vectors[VEC_UNIMPII] = unimp_vec;
+	}
 }
 
 void set_evector(int vecnum, void (*handler)(void))
@@ -176,10 +171,11 @@
 
 extern void die_if_kernel(char *,struct pt_regs *,int);
 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-			      unsigned long error_code);
+                             unsigned long error_code);
 
 asmlinkage void trap_c(struct frame *fp);
 
+#if defined (CONFIG_M68060)
 static inline void access_error060 (struct frame *fp)
 {
 	unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
@@ -208,7 +204,7 @@
 		printk("errorcode = %d\n", errorcode );
 #endif
 		if (fslw & MMU060_MA)
-		  addr = PAGE_ALIGN(addr);
+			addr = PAGE_ALIGN(addr);
 		do_page_fault( (struct pt_regs *)fp, addr, errorcode );
 	}
 	else {
@@ -216,7 +212,9 @@
 		trap_c( fp );
 	}
 }
+#endif /* CONFIG_M68060 */
 
+#if defined (CONFIG_M68040)
 static unsigned long probe040 (int iswrite, int fc, unsigned long addr)
 {
 	unsigned long mmusr;
@@ -224,8 +222,8 @@
 
 	set_fs (fc);
 
-  	if (iswrite)
-  		/* write */
+	if (iswrite)
+		/* write */
 		asm volatile ("movel %1,%/a0\n\t"
 			      ".word 0xf548\n\t"	/* ptestw (a0) */
 			      ".long 0x4e7a8805\n\t"	/* movec mmusr,a0 */
@@ -242,7 +240,6 @@
 			      : "g" (addr)
 			      : "a0");
 
-
 	set_fs (fs);
 
 	return mmusr;
@@ -351,14 +348,19 @@
 				 fp->un.fmt7.wb3a, fp->un.fmt7.wb3d,
 				 fp);
 }
+#endif /* CONFIG_M68040 */
 
+#if defined(CONFIG_M68020_OR_M68030)
 static inline void bus_error030 (struct frame *fp)
 {
 	volatile unsigned short temp;
 	unsigned short mmusr;
-	unsigned long addr, desc, errorcode;
+	unsigned long addr, errorcode;
 	unsigned short ssw = fp->un.fmtb.ssw;
 	int user_space_fault = 1;
+#if DEBUG
+	unsigned long desc;
+#endif
 
 #if DEBUG
 	printk ("pid = %x  ", current->pid);
@@ -414,14 +416,20 @@
 	  {
 	    addr = fp->un.fmtb.daddr;
 
+	    mmusr = MMU_I;
 	    if (user_space_fault) {
+#if DEBUG
 		    asm volatile ("ptestr #1,%2@,#7,%0\n\t"
 				  "pmove %/psr,%1@"
 				  : "=a&" (desc)
 				  : "a" (&temp), "a" (addr));
+#else
+		    asm volatile ("ptestr #1,%1@,#7\n\t"
+				  "pmove %/psr,%0@"
+				  : : "a" (&temp), "a" (addr));
+#endif
 		    mmusr = temp;
-	    } else
-		    mmusr = MMU_I;
+	    }
       
 #if DEBUG
 	    printk ("mmusr is %#x for addr %#lx in task %p\n",
@@ -431,16 +439,10 @@
 #endif
 
 	    errorcode = (mmusr & MMU_I) ? 0 : 1;
-	      /* if (!(ssw & RW)) updated to 1.2.13pl6 */
- 	    if (!(ssw & RW) || ssw & RM)
+	    if (!(ssw & RW) || ssw & RM)
 		    errorcode |= 2;
 
-	    if (mmusr & MMU_I)
-		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
-
-	    /* else if ((mmusr & MMU_WP) && !(ssw & RW)) */
-
- 	    else if ((mmusr & MMU_WP) && (!(ssw & RW) || ssw & RM))
+	    if (mmusr & (MMU_I | MMU_WP))
 		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
 	    else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
 		    printk ("invalid %s access at %#lx from pc %#lx\n",
@@ -450,7 +452,7 @@
 		    force_sig(SIGSEGV, current);
 		    return;
 	    } else {
-#ifdef DEBUG
+#if 0
 		    static volatile long tlong;
 #endif
 
@@ -484,12 +486,13 @@
 
 	    /* setup an ATC entry for the access about to be retried */
 	    if (!(ssw & RW))
-		    asm volatile ("ploadw #1,%0@" : /* no outputs */
-				  : "a" (addr));
+		    asm volatile ("ploadw %1,%0@" : /* no outputs */
+				  : "a" (addr), "d" (ssw));
 	    else
-		    asm volatile ("ploadr #1,%0@" : /* no outputs */
-				  : "a" (addr));
+		    asm volatile ("ploadr %1,%0@" : /* no outputs */
+				  : "a" (addr), "d" (ssw));
 
+#if 0
 	    /* If this was a data fault due to an invalid page and a
 	       prefetch is pending on the same page, simulate it (but
 	       only if the page is now valid).  Otherwise we'll get an
@@ -525,38 +528,41 @@
 		      }
 		  }
 	      }
+#endif
 	  }
 
 	/* Now handle the instruction fault. */
 
+	if (!(ssw & (FC|FB)))
+		return;
+
 	/* get the fault address */
-	if ((fp->ptregs.format) == 0xA )
-		if (ssw & FC)
-			addr = fp->ptregs.pc + 2;
-		else if (ssw & FB)
-			addr = fp->ptregs.pc + 4;
-		else
-			return;
+	if (fp->ptregs.format == 10)
+		addr = fp->ptregs.pc + 4;
 	else
-		if (ssw & FC)
-			addr = fp->un.fmtb.baddr - 2;
-		else if (ssw & FB)
-			addr = fp->un.fmtb.baddr;
-		else
-			return;
+		addr = fp->un.fmtb.baddr;
+	if (ssw & FC)
+		addr -= 2;
 
 	if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
-		/* Insn fault on same page as data fault */
-		return;
+		/* Insn fault on same page as data fault.  But we
+		   should still create the ATC entry.  */
+		goto create_atc_entry;
 
+	mmusr = MMU_I;
 	if (user_space_fault) {
+#if DEBUG
 		asm volatile ("ptestr #1,%2@,#7,%0\n\t"
 			      "pmove %/psr,%1@"
 			      : "=a&" (desc)
 			      : "a" (&temp), "a" (addr));
+#else
+		asm volatile ("ptestr #1,%1@,#7\n\t"
+			      "pmove %/psr,%0@"
+			      : : "a" (&temp), "a" (addr));
+#endif
 		mmusr = temp;
-	} else
-		mmusr = MMU_I;
+	}
       
 #ifdef DEBUG
 	printk ("mmusr is %#x for addr %#lx in task %p\n",
@@ -565,10 +571,8 @@
 		mm_ptov(desc), *(unsigned long *)mm_ptov(desc));
 #endif
 
-	errorcode = (mmusr & MMU_I) ? 0 : 1;
-
 	if (mmusr & MMU_I)
-		do_page_fault ((struct pt_regs *)fp, addr, errorcode);
+		do_page_fault ((struct pt_regs *)fp, addr, 0);
 	else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
 		printk ("invalid insn access at %#lx from pc %#lx\n",
 			addr, fp->ptregs.pc);
@@ -579,6 +583,8 @@
 		force_sig(SIGSEGV, current);
 		return;
 	} else {
+#if 0 /* stale ATC entry??  Ignore it */
+
 #ifdef DEBUG
 		static volatile long tlong;
 #endif
@@ -605,18 +611,22 @@
 		}
 
 #endif
+
 #if DEBUG
 		printk("Unknown SIGSEGV - 3\n");
 #endif
 		die_if_kernel("Oops",&fp->ptregs,mmusr);
 		force_sig(SIGSEGV, current);
 		return;
+#endif
 	}
 
+create_atc_entry:
 	/* setup an ATC entry for the access about to be retried */
-	asm volatile ("ploadr #1,%0@" : /* no outputs */
+	asm volatile ("ploadr #2,%0@" : /* no outputs */
 		      : "a" (addr));
 }
+#endif /* CONFIG_M68020_OR_M68030 */
 
 asmlinkage void buserr_c(struct frame *fp)
 {
@@ -629,16 +639,22 @@
 #endif
 
 	switch (fp->ptregs.format) {
+#if defined (CONFIG_M68060)
 	case 4:				/* 68060 access error */
 	  access_error060 (fp);
 	  break;
+#endif
+#if defined (CONFIG_M68040)
 	case 0x7:			/* 68040 access error */
 	  access_error040 (fp);
 	  break;
+#endif
+#if defined (CONFIG_M68020_OR_M68030)
 	case 0xa:
 	case 0xb:
 	  bus_error030 (fp);
 	  break;
+#endif
 	default:
 	  die_if_kernel("bad frame format",&fp->ptregs,0);
 #if DEBUG
@@ -673,7 +689,7 @@
 	    addr += sizeof(fp->un.fmt3);
 	    break;
 	case 0x4:
-	    printk((m68k_is040or060 == 6 ? "fault addr=%08lx fslw=%08lx\n"
+	    printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
 		    : "eff addr=%08lx pc=%08lx\n"),
 		   fp->un.fmt4.effaddr, fp->un.fmt4.pc);
 	    addr += sizeof(fp->un.fmt4);
@@ -767,8 +783,7 @@
 		printk ("*** Exception %d ***   FORMAT=%X\n",
 			(fp->ptregs.vector) >> 2, 
 			fp->ptregs.format);
-	if (((fp->ptregs.vector) >> 2) == VEC_ADDRERR
-	    && !m68k_is040or060) {
+	if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
 		unsigned short ssw = fp->un.fmtb.ssw;
 
 		printk ("SSW=%#06x  ", ssw);
@@ -871,7 +886,7 @@
 		break;
 	}
 
-	force_sig (sig, current);
+	send_sig (sig, current, 1);
 }
 
 asmlinkage void set_esp0 (unsigned long ssp)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/lib/Makefile linux/arch/m68k/lib/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/lib/Makefile	Mon Apr  1 21:37:48 1996
+++ linux/arch/m68k/lib/Makefile	Wed Sep 25 10:47:40 1996
@@ -2,7 +2,10 @@
 # Makefile for m68k-specific library files..
 #
 
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
+
 L_TARGET = lib.a
-L_OBJS  = ashrdi3.o checksum.o memcpy.o memcmp.o
+L_OBJS  = ashrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/lib/memcpy.c linux/arch/m68k/lib/memcpy.c
--- lx2.0/v2.0.21/linux/arch/m68k/lib/memcpy.c	Wed Dec 27 22:46:35 1995
+++ linux/arch/m68k/lib/memcpy.c	Wed Sep 25 10:47:40 1996
@@ -3,7 +3,7 @@
 void * memcpy(void * to, const void * from, size_t n)
 {
   void *xto = to;
-  size_t temp;
+  size_t temp, temp1;
 
   if (!n)
     return xto;
@@ -30,10 +30,30 @@
     {
       long *lto = to;
       const long *lfrom = from;
-      temp--;
-      do
-	*lto++ = *lfrom++;
-      while (temp--);
+
+      __asm__ __volatile__("movel %2,%3\n\t"
+			   "andw  #7,%3\n\t"
+			   "lsrl  #3,%2\n\t"
+			   "negw  %3\n\t"
+			   "jmp   %%pc@(1f,%3:w:2)\n\t"
+			   "4:\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "movel %0@+,%1@+\n\t"
+			   "1:\t"
+			   "dbra  %2,4b\n\t"
+			   "clrw  %2\n\t"
+			   "subql #1,%2\n\t"
+			   "jpl   4b\n\t"
+			   : "=a" (lfrom), "=a" (lto), "=d" (temp),
+			   "=&d" (temp1)
+			   : "0" (lfrom), "1" (lto), "2" (temp)
+			   );
       to = lto;
       from = lfrom;
     }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/lib/memset.c linux/arch/m68k/lib/memset.c
--- lx2.0/v2.0.21/linux/arch/m68k/lib/memset.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/memset.c	Wed Sep 25 10:47:40 1996
@@ -0,0 +1,68 @@
+#include <linux/types.h>
+
+void * memset(void * s, int c, size_t count)
+{
+  void *xs = s;
+  size_t temp, temp1;
+
+  if (!count)
+    return xs;
+  c &= 0xff;
+  c |= c << 8;
+  c |= c << 16;
+  if ((long) s & 1)
+    {
+      char *cs = s;
+      *cs++ = c;
+      s = cs;
+      count--;
+    }
+  if (count > 2 && (long) s & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+      count -= 2;
+    }
+  temp = count >> 2;
+  if (temp)
+    {
+      long *ls = s;
+
+      __asm__ __volatile__("movel %1,%2\n\t"
+			   "andw  #7,%2\n\t"
+			   "lsrl  #3,%1\n\t"
+			   "negw  %2\n\t"
+			   "jmp   %%pc@(2f,%2:w:2)\n\t"
+			   "1:\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "movel %3,%0@+\n\t"
+			   "2:\t"
+			   "dbra  %1,1b\n\t"
+			   "clrw  %1\n\t"
+			   "subql #1,%1\n\t"
+			   "jpl   1b\n\t"
+			   : "=a" (ls), "=d" (temp), "=&d" (temp1)
+			   : "d" (c), "0" (ls), "1" (temp)
+			   );
+      s = ls;
+    }
+  if (count & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+    }
+  if (count & 1)
+    {
+      char *cs = s;
+      *cs = c;
+    }
+  return xs;
+}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S
--- lx2.0/v2.0.21/linux/arch/m68k/lib/semaphore.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/semaphore.S	Wed Sep 25 10:47:40 1996
@@ -0,0 +1,29 @@
+/*
+ *  linux/arch/m68k/lib/semaphore.S
+ *
+ *  Copyright (C) 1996  Linus Torvalds
+ *
+ *  m68k version by Andreas Schwab
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * "down_failed" is called with the eventual return address
+ * in %a0, and the address of the semaphore in %a1. We need
+ * to increment the number of waiters on the semaphore,
+ * call "__down()", and then eventually return to try again.
+ */
+ENTRY(down_failed)
+	movel %a0,-(%sp)
+	movel %a1,-(%sp)
+	jbsr SYMBOL_NAME(__down)
+	movel (%sp)+,%a1
+	rts
+
+ENTRY(up_wakeup)
+	movel %a0,-(%sp)
+	movel %a1,-(%sp)
+	jbsr SYMBOL_NAME(__up)
+	movel (%sp)+,%a1
+	rts
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- lx2.0/v2.0.21/linux/arch/m68k/mm/fault.c	Mon May  6 12:44:30 1996
+++ linux/arch/m68k/mm/fault.c	Wed Sep 25 10:47:40 1996
@@ -29,14 +29,17 @@
 			      unsigned long error_code)
 {
 	struct vm_area_struct * vma;
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
 
 #ifdef DEBUG
 	printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
 		regs->sr, regs->pc, address, error_code,
-		current->tss.pagedir_v);
+		tsk->tss.pagedir_v);
 #endif
 
-	vma = find_vma(current, address);
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, address);
 	if (!vma)
 	  goto bad_area;
 	if (vma->vm_start <= address)
@@ -73,17 +76,18 @@
 	    goto bad_area;
 	}
 	if (error_code & 1) {
-		do_wp_page(current, vma, address, error_code & 2);
+		do_wp_page(tsk, vma, address, error_code & 2);
+		up(&mm->mmap_sem);
 		return 0;
 	}
-	do_no_page(current, vma, address, error_code & 2);
+	do_no_page(tsk, vma, address, error_code & 2);
+	up(&mm->mmap_sem);
 
 	/* There seems to be a missing invalidate somewhere in do_no_page.
 	 * Until I found it, this one cures the problem and makes
 	 * 1.2 run on the 68040 (Martin Apel).
 	 */
-	flush_tlb_all();
-
+	flush_tlb_page(vma, address);
 	return 0;
 
 /*
@@ -91,9 +95,10 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
+	up(&mm->mmap_sem);
 	if (user_mode(regs)) {
 		/* User memory access */
-		force_sig (SIGSEGV, current);
+		force_sig (SIGSEGV, tsk);
 		return 1;
 	}
 
@@ -111,3 +116,4 @@
 
 	return 1;
 }
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- lx2.0/v2.0.21/linux/arch/m68k/mm/init.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/mm/init.c	Wed Sep 25 10:47:40 1996
@@ -16,21 +16,16 @@
 #include <linux/blk.h>
 #endif
 
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/bootinfo.h>
 #include <asm/machdep.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void init_kpointer_table(void);
 extern void show_net_buffers(void);
-extern unsigned long mm_phys_to_virt (unsigned long addr);
-extern char *rd_start;
-extern int rd_doload;
-
-unsigned long ramdisk_length;
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -94,14 +89,12 @@
 #endif
 }
 
-#if 0 /* The 68030 doesn't care about reserved bits. */
 /*
  * Bits to add to page descriptors for "normal" caching mode.
  * For 68020/030 this is 0.
  * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
  */
-unsigned long mm_cachebits;
-#endif
+unsigned long mm_cachebits = 0;
 
 pte_t *kernel_page_table (unsigned long *memavailp)
 {
@@ -122,7 +115,6 @@
 #define ONEMEG	(1024*1024)
 #define L3TREESIZE (256*1024)
 
-	int is040 = m68k_is040or060;
 	static unsigned long mem_mapped = 0;
 	static unsigned long virtaddr = 0;
 	static pte_t *ktablep = NULL;
@@ -158,7 +150,7 @@
 	 * arch/head.S
 	 *
 	 */
-	if (is040 && mem_mapped == 0)
+	if (CPU_IS_040_OR_060 && mem_mapped == 0)
 		ktablep = kpt;
 
 	for (physaddr = addr;
@@ -180,7 +172,7 @@
 			pindex = 0;
 		}
 
-		if (is040) {
+		if (CPU_IS_040_OR_060) {
 			int i;
 			unsigned long ktable;
 
@@ -306,30 +298,14 @@
 #endif
 
 	init_kpointer_table();
-#if 0
-	/*
-	 * Setup cache bits
-	 */
-	mm_cachebits = m68k_is040or060 ? _PAGE_CACHE040 : 0;
 
-	/* Initialize protection map.  */
-	protection_map[0] = PAGE_READONLY;
-	protection_map[1] = PAGE_READONLY;
-	protection_map[2] = PAGE_COPY;
-	protection_map[3] = PAGE_COPY;
-	protection_map[4] = PAGE_READONLY;
-	protection_map[5] = PAGE_READONLY;
-	protection_map[6] = PAGE_COPY;
-	protection_map[7] = PAGE_COPY;
-	protection_map[8] = PAGE_READONLY;
-	protection_map[9] = PAGE_READONLY;
-	protection_map[10] = PAGE_SHARED;
-	protection_map[11] = PAGE_SHARED;
-	protection_map[12] = PAGE_READONLY;
-	protection_map[13] = PAGE_READONLY;
-	protection_map[14] = PAGE_SHARED;
-	protection_map[15] = PAGE_SHARED;
-#endif
+	/* Fix the cache mode in the page descriptors for the 680[46]0.  */
+	if (CPU_IS_040_OR_060) {
+		int i;
+		mm_cachebits = _PAGE_CACHE040;
+		for (i = 0; i < 16; i++)
+			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
+	}
 
 	/*
 	 * Map the physical memory available into the kernel virtual
@@ -394,17 +370,18 @@
 	task[0]->tss.crp[0] = 0x80000000 | _PAGE_SHORT;
 	task[0]->tss.crp[1] = task[0]->tss.pagedir_p;
 
-	if (m68k_is040or060)
-		asm ("movel %0,%/d0\n\t"
-		     ".long 0x4e7b0806" /* movec d0,urp */
-		     : /* no outputs */
-		     : "g" (task[0]->tss.crp[1])
-		     : "d0");
+	if (CPU_IS_040_OR_060)
+		asm __volatile__ ("movel %0,%/d0\n\t"
+				  ".long 0x4e7b0806" /* movec d0,urp */
+				  : /* no outputs */
+				  : "g" (task[0]->tss.crp[1])
+				  : "d0");
 	else
-		asm ("pmove %0@,%/crp"
-		     : /* no outputs */
-		     : "a" (task[0]->tss.crp));
-
+		asm __volatile__ ("movel %0,%/a0\n\t"
+				  ".long 0xf0104c00" /* pmove %/a0@,%/crp */
+				  : /* no outputs */
+				  : "g" (task[0]->tss.crp)
+				  : "a0");
 #ifdef DEBUG
 	printk ("set crp\n");
 #endif
@@ -418,34 +395,6 @@
 	printk ("before free_area_init\n");
 #endif
 
-#ifdef CONFIG_BLK_DEV_RAM
-#ifndef CONFIG_BLK_DEV_INITRD
-	/*
-	 * Since the initialization of the ramdisk's has been changed
-	 * so it fits the new driver initialization scheme, we have to
-	 * make room for our preloaded image here, instead of doing it
-	 * in rd_init() as we cannot kmalloc() a block large enough
-	 * for the image.
-	 */
-
-	ramdisk_length = boot_info.ramdisk_size * 1024;
-
-	if ((ramdisk_length > 0) && (ROOT_DEV == 0)) {
-	  char *rdp;	     /* current location of ramdisk */
-
-	  rd_start = (char *) start_mem;
-
-	  /* get current address of ramdisk */
-	  rdp = (char *)mm_phys_to_virt (boot_info.ramdisk_addr);
-
-	  /* copy the ram disk image */
-	  memcpy (rd_start, rdp, ramdisk_length);
-	  start_mem += ramdisk_length;
-	  rd_doload = 1;     /* tell rd_load to load this thing */
-	}
-#endif
-#endif
-
 	return free_area_init (start_mem, end_mem);
 }
 
@@ -512,7 +461,8 @@
 		}
 		mem_map[MAP_NR(tmp)].count = 1;
 #ifdef CONFIG_BLK_DEV_INITRD
-		if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
+		if (!initrd_start ||
+		    (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end))
 #endif
 			free_page(tmp);
 	}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- lx2.0/v2.0.21/linux/arch/m68k/mm/memory.c	Thu May 16 09:05:10 1996
+++ linux/arch/m68k/mm/memory.c	Wed Sep 25 10:47:40 1996
@@ -10,13 +10,13 @@
 #include <linux/types.h>
 #include <linux/malloc.h>
 
+#include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/amigahw.h>
-#include <asm/bootinfo.h>
 
 extern pte_t *kernel_page_table (unsigned long *memavailp);
 
@@ -275,7 +275,7 @@
 	/* not in one of the memory chunks; get the actual
 	 * physical address from the MMU.
 	 */
-	if (m68k_is040or060 == 6) {
+	if (CPU_IS_060) {
 	  unsigned long fs = get_fs();
 	  unsigned long  paddr;
 
@@ -294,7 +294,7 @@
 
 	  return paddr;
 
-	} else if (m68k_is040or060 == 4) {
+	} else if (CPU_IS_040) {
 	  unsigned long mmusr;
 	  unsigned long fs = get_fs();
 
@@ -414,17 +414,18 @@
 
 /* push and invalidate page in both caches */
 #define	pushcl040(paddr) do { push040((paddr));\
-			      if (m68k_is040or060 == 6) clear040((paddr));\
+			      if (CPU_IS_060) clear040((paddr));\
 			 } while(0)
 
 /* push page in both caches, invalidate in i-cache */
 #define	pushcli040(paddr) do { push040((paddr));\
-			       if (m68k_is040or060 == 6) cleari040((paddr));\
+			       if (CPU_IS_060) cleari040((paddr));\
 			  } while(0)
 
 /* push page defined by virtual address in both caches */
 #define	pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
 					      /* ptestr (a0) */\
+					      "nop\n\t"\
 					      ".word 0xf568\n\t"\
 					      /* movec mmusr,d0 */\
 					      ".long 0x4e7a0805\n\t"\
@@ -474,13 +475,30 @@
 
 void cache_clear (unsigned long paddr, int len)
 {
-    if (m68k_is040or060) {
-	/* ++roman: There have been too many problems with the CINV, it seems
-	 * to break the cache maintenance of DMAing drivers. I don't expect
-	 * too much overhead by using CPUSH instead.
+    if (CPU_IS_040_OR_060) {
+	/*
+	 * cwe need special treatment for the first page, in case it
+	 * is not page-aligned.
 	 */
+	if (paddr & (PAGE_SIZE - 1)){
+	    pushcl040(paddr);
+	    if (len <= PAGE_SIZE){
+		if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
+		    pushcl040(paddr + len - 1);
+		}
+		return;
+	    }else{
+		len -=PAGE_SIZE;
+		paddr += PAGE_SIZE;
+	    }
+	}
+		
 	while (len > PAGE_SIZE) {
+#if 0
 	    pushcl040(paddr);
+#else
+	    clear040(paddr);
+#endif
 	    len -= PAGE_SIZE;
 	    paddr += PAGE_SIZE;
 	}
@@ -492,22 +510,6 @@
 	    }
 	}
     }
-#if 0
-	/* on 68040, invalidate cache lines for pages in the range */
-	while (len > PAGE_SIZE) {
-	    clear040(paddr);
-	    len -= PAGE_SIZE;
-	    paddr += PAGE_SIZE;
-	    }
-	if (len > 0) {
-	    /* 0 < len <= PAGE_SIZE */
-	    clear040(paddr);
-	    if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) {
-		/* a page boundary gets crossed at the end */
-		clear040(paddr + len - 1);
-		}
-	    }
-#endif
     else /* 68030 or 68020 */
 	asm volatile ("movec %/cacr,%/d0\n\t"
 		      "oriw %0,%/d0\n\t"
@@ -526,7 +528,7 @@
 
 void cache_push (unsigned long paddr, int len)
 {
-    if (m68k_is040or060) {
+    if (CPU_IS_040_OR_060) {
 	/*
          * on 68040 or 68060, push cache lines for pages in the range;
 	 * on the '040 this also invalidates the pushed lines, but not on
@@ -539,9 +541,6 @@
 	    }
 	if (len > 0) {
 	    pushcli040(paddr);
-#if 0
-	    if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) {
-#endif
 	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
 		/* a page boundary gets crossed at the end */
 		pushcli040(paddr + len - 1);
@@ -578,7 +577,7 @@
 
 void cache_push_v (unsigned long vaddr, int len)
 {
-    if (m68k_is040or060 == 4) {
+    if (CPU_IS_040) {
 	/* on 68040, push cache lines for pages in the range */
 	while (len > PAGE_SIZE) {
 	    pushv040(vaddr);
@@ -587,16 +586,13 @@
 	    }
 	if (len > 0) {
 	    pushv040(vaddr);
-#if 0
-	    if (((vaddr + len - 1) / PAGE_SIZE) != (vaddr / PAGE_SIZE)) {
-#endif
 	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
 		/* a page boundary gets crossed at the end */
 		pushv040(vaddr + len - 1);
 		}
 	    }
 	}
-    else if (m68k_is040or060 == 6) {
+    else if (CPU_IS_060) {
 	/* on 68040, push cache lines for pages in the range */
 	while (len > PAGE_SIZE) {
 	    pushv060(vaddr);
@@ -670,7 +666,7 @@
 	 * mapped... */
 	size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1);
 
-	if (m68k_is040or060) {
+	if (CPU_IS_040_OR_060) {
 		prot = _PAGE_PRESENT | _PAGE_GLOBAL040;
 		switch( nocacheflag ) {
 		  case KERNELMAP_FULL_CACHING:
@@ -697,7 +693,7 @@
 	if (pgd_present(*page_dir)) {
 		kpointerp = (pmd_t *)pgd_page(*page_dir);
 		pindex = (vaddr >> 18) & 0x7f;
-		if (pindex != 0 && m68k_is040or060) {
+		if (pindex != 0 && CPU_IS_040_OR_060) {
 			if (pmd_present(*kpointerp))
 				ktablep = (pte_t *)pmd_page(*kpointerp);
 			else {
@@ -727,7 +723,7 @@
 			pindex = 0;
 		}
 
-		if (m68k_is040or060) {
+		if (CPU_IS_040_OR_060) {
 			int i;
 			unsigned long ktable;
 
@@ -838,7 +834,7 @@
 	pgd_t *dir = pgd_offset_k( address );
 	unsigned long end = address + size;
 	
-	if (m68k_is040or060) {
+	if (CPU_IS_040_OR_060) {
 		switch( cmode ) {
 		  case KERNELMAP_FULL_CACHING:
 			cmode = _PAGE_CACHE040;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/tools/amiga/Makefile linux/arch/m68k/tools/amiga/Makefile
--- lx2.0/v2.0.21/linux/arch/m68k/tools/amiga/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/tools/amiga/Makefile	Wed Sep 25 10:47:40 1996
@@ -0,0 +1,22 @@
+
+CC =		m68k-cbm-amigados-gcc
+CFLAGS =	-Wall -O2
+
+
+All:		dmesg
+
+
+dmesg:		dmesg.c
+		$(CC) $(CFLAGS) -o dmesg dmesg.c -noixemul
+
+
+CC =		m68k-cbm-amigados-gcc
+CFLAGS =	-Wall -O2
+
+
+All:		dmesg
+
+
+dmesg:		dmesg.c
+		$(CC) $(CFLAGS) -o dmesg dmesg.c -noixemul
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/tools/amiga/dmesg.c linux/arch/m68k/tools/amiga/dmesg.c
--- lx2.0/v2.0.21/linux/arch/m68k/tools/amiga/dmesg.c	Mon May 20 07:54:27 1996
+++ linux/arch/m68k/tools/amiga/dmesg.c	Wed Sep 25 10:47:40 1996
@@ -7,10 +7,6 @@
  *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
  *
  *
- *  Compilation (under AmigaOS):
- *
- *	gcc -o dmesg dmesg.c -noixemul -idirafter INCLUDE: -Wall -s -O3
- *
  *  Usage:
  *
  *	dmesg
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- lx2.0/v2.0.21/linux/drivers/block/floppy.c	Mon Sep  2 15:18:25 1996
+++ linux/drivers/block/floppy.c	Sat Sep 28 23:05:16 1996
@@ -1043,7 +1043,7 @@
 	fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
 	fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
 			DMA_MODE_READ : DMA_MODE_WRITE);
-	fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data));
+	fd_set_dma_addr(raw_cmd->kernel_data);
 	fd_set_dma_count(raw_cmd->length);
 	virtual_dma_port = FDCS->address;
 	fd_enable_dma();
@@ -2087,7 +2087,7 @@
 
 	/* determine interleave */
 	il = 1;
-	if (_floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
+	if (_floppy->fmt_gap < 0x22)
 		il++;
 
 	/* initialize field */
@@ -3485,8 +3485,8 @@
 		printk("\n");
 }
 
-static int floppy_read(struct inode * inode, struct file * filp,
-		       char * buf, int count)
+static long floppy_read(struct inode * inode, struct file * filp,
+		       char * buf, unsigned long count)
 {
 	int drive = DRIVE(inode->i_rdev);
 
@@ -3496,8 +3496,8 @@
 	return block_read(inode, filp, buf, count);
 }
 
-static int floppy_write(struct inode * inode, struct file * filp,
-			const char * buf, int count)
+static long floppy_write(struct inode * inode, struct file * filp,
+			const char * buf, unsigned long count)
 {
 	int block;
 	int ret;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- lx2.0/v2.0.21/linux/drivers/block/ide-tape.c	Wed Sep 11 17:57:13 1996
+++ linux/drivers/block/ide-tape.c	Fri Sep 27 08:27:12 1996
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.7 - ALPHA	Sep  10, 1996
+ * linux/drivers/block/ide-tape.c	Version 1.8 - ALPHA	Sep  26, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -187,6 +187,8 @@
  * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
  *                       Fixed end of media bug.
  * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
+ *                        interactive response and high system throughput.
  *
  * We are currently in an *alpha* stage. The driver is not complete and not
  * much tested. I would strongly suggest to:
@@ -1228,6 +1230,10 @@
 {
 	idetape_tape_t *tape=&(drive->tape);
 	unsigned int allocation_length;
+#if IDETAPE_ANTICIPATE_READ_WRITE_DSC
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long t1, tmid, tn;
+#endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
 
 #if IDETAPE_DEBUG_LOG
 	printk ("ide-tape: Reached idetape_setup\n");
@@ -1310,10 +1316,28 @@
 	 *	constantly streaming.
 	 */
 
-	if (tape->max_number_of_stages)	
-		tape->best_dsc_rw_frequency = (unsigned long) ((tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125));
-	else
-		tape->best_dsc_rw_frequency = (unsigned long) ((tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000));
+	/*
+	 *	We will ignore the above algorithm for now, as it can have
+	 *	a bad effect on interactive response under some conditions.
+	 *	The following attempts to find a balance between good latency
+	 *	and good system throughput. It will be nice to have all this
+	 *	configurable in run time at some point.
+	 */
+	t1 = (tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
+	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125);
+	tn = (IDETAPE_FIFO_THRESHOLD * tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000);
+
+	if (tape->max_number_of_stages) {
+		if (drive->using_dma)
+			tape->best_dsc_rw_frequency = tmid;
+		else {
+			if (hwif->drives[drive->select.b.unit ^ 1].present || hwif->next != hwif)
+				tape->best_dsc_rw_frequency = IDETAPE_MIN ((tn + tmid) / 2, tmid);
+			else
+				tape->best_dsc_rw_frequency = IDETAPE_MIN (tn, tmid);
+		}
+	} else
+		tape->best_dsc_rw_frequency = t1;
 
 	/*
 	 *	Ensure that the number we got makes sense.
@@ -1336,8 +1360,10 @@
 	tape->best_dsc_rw_frequency=IDETAPE_DSC_READ_WRITE_FALLBACK_FREQUENCY;
 #endif /* IDETAPE_ANTICIPATE_READ_WRITE_DSC */
 
-	printk ("ide-tape: Tape speed - %d KBps. Recommended transfer unit - %d bytes.\n",tape->capabilities.speed,tape->data_buffer_size);
-
+	printk (KERN_INFO "ide-tape: %s <-> %s, %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
+		drive->name, "ht0", tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->data_buffer_size,
+		tape->data_buffer_size / 1024, tape->max_number_of_stages * tape->data_buffer_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
 	return;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h
--- lx2.0/v2.0.21/linux/drivers/block/ide-tape.h	Wed Sep 11 17:57:13 1996
+++ linux/drivers/block/ide-tape.h	Fri Sep 27 08:27:12 1996
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.h	Version 1.7 - ALPHA	Sep  10, 1996
+ * linux/drivers/block/ide-tape.h	Version 1.8 - ALPHA	Sep  26, 1996
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -232,6 +232,15 @@
  */
 
 #define IDETAPE_ANTICIPATE_READ_WRITE_DSC	1
+
+/*
+ *	The following parameter is used to select the point in the internal
+ *	tape fifo in which we will start to refill the buffer. Decreasing
+ *	the following parameter will improve the system's latency and
+ *	interactive response, while using a high value might improve sytem
+ *	throughput.
+ */
+#define	IDETAPE_FIFO_THRESHOLD 			2
 
 /*
  *	DSC timings.
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- lx2.0/v2.0.21/linux/drivers/block/ide.c	Sat Aug 17 21:19:26 1996
+++ linux/drivers/block/ide.c	Fri Sep 27 08:27:12 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.51  Aug  10, 1996
+ *  linux/drivers/block/ide.c	Version 5.52  Sep  24, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -259,6 +259,8 @@
  * Version 5.50		allow values as small as 20 for idebus=
  * Version 5.51		force non io_32bit in drive_cmd_intr()
  *			change delay_10ms() to delay_50ms() to fix problems
+ * Version 5.52		fix incorrect invalidation of removable devices
+ *			add "hdx=slow" command line option
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -485,8 +487,18 @@
 		} else
 #endif /* SUPPORT_VLB_SYNC */
 			insl(data_reg, buffer, wcount);
-	} else
-		insw(data_reg, buffer, wcount<<1);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				*ptr++ = inw_p(data_reg);
+				*ptr++ = inw_p(data_reg);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			insw(data_reg, buffer, wcount<<1);
+	}
 }
 
 /*
@@ -509,8 +521,18 @@
 		} else
 #endif /* SUPPORT_VLB_SYNC */
 			outsl(data_reg, buffer, wcount);
-	} else
-		outsw(data_reg, buffer, wcount<<1);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				outw_p(*ptr++, data_reg);
+				outw_p(*ptr++, data_reg);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			outsw(data_reg, buffer, wcount<<1);
+	}
 }
 
 /*
@@ -684,6 +706,7 @@
 		hwgroup->poll_timeout = 0;	/* end of polling */
 		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
 		do_reset1 (drive, 1);	/* do it the old fashioned way */
+		return;
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
 }
@@ -1874,7 +1897,7 @@
 	if (drive->media == ide_tape)
 		return idetape_blkdev_open (inode, filp, drive);
 #endif	/* CONFIG_BLK_DEV_IDETAPE */
-	if (drive->removable) {
+	if (drive->removable && drive->usage == 1) {
 		byte door_lock[] = {WIN_DOORLOCK,0,0,0};
 		struct request rq;
 		check_disk_change(inode->i_rdev);
@@ -1955,7 +1978,7 @@
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
 		if (drive->part[p].nr_sects > 0) {
 			kdev_t devp = MKDEV(major, minor+p);
-			sync_dev           (devp);
+			fsync_dev          (devp);
 			invalidate_inodes  (devp);
 			invalidate_buffers (devp);
 		}
@@ -2865,7 +2888,8 @@
 	 */
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
 		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
-				"serialize", "autotune", "noautotune", NULL};
+				"serialize", "autotune", "noautotune",
+				"slow", NULL};
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
 		unit = unit % MAX_DRIVES;
@@ -2894,6 +2918,9 @@
 				goto done;
 			case -7: /* "noautotune" */
 				drive->autotune = 2;
+				goto done;
+			case -8: /* "slow" */
+				drive->slow = 1;
 				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- lx2.0/v2.0.21/linux/drivers/block/ide.h	Sat Aug 10 10:03:14 1996
+++ linux/drivers/block/ide.h	Mon Sep 30 11:20:10 1996
@@ -25,6 +25,9 @@
 #undef REALLY_FAST_IO			/* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
 
+#ifndef SUPPORT_SLOW_DATA_PORTS		/* 1 to support slow data ports */
+#define SUPPORT_SLOW_DATA_PORTS	1	/* 0 to reduce kernel size */
+#endif
 #ifndef SUPPORT_VLB_SYNC		/* 1 to support weird 32-bit chips */
 #define SUPPORT_VLB_SYNC	1	/* 0 to reduce kernel size */
 #endif
@@ -327,6 +330,7 @@
 	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
 	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
 	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
+	unsigned slow		: 1;	/* flag: slow data port */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 #if FAKE_FDISK_FOR_EZDRIVE
 	unsigned remap_0_to_1	: 1;	/* flag: partitioned with ezdrive */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- lx2.0/v2.0.21/linux/drivers/block/triton.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/block/triton.c	Sun Sep 22 09:53:44 1996
@@ -128,7 +128,8 @@
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
 				 "CONNER CTMA 4000",
-				 "CONNER CTT8000-A"};
+				 "CONNER CTT8000-A",
+				 NULL};
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- lx2.0/v2.0.21/linux/drivers/block/xd.c	Sun Sep  8 19:50:20 1996
+++ linux/drivers/block/xd.c	Sat Sep 28 11:46:40 1996
@@ -29,7 +29,6 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/genhd.h>
-#include <linux/xd.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -39,6 +38,8 @@
 #define MAJOR_NR XT_DISK_MAJOR
 #include <linux/blk.h>
 
+#include "xd.h"
+
 XD_INFO xd_info[XD_MAXDRIVES];
 
 /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
@@ -77,11 +78,12 @@
 	{ 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
 	{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
 };
-static u_char *xd_bases[] =
+
+static unsigned int xd_bases[] =
 {
-	(u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xCC000,
-	(u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD8000,
-	(u_char *) 0xE0000
+	0xC8000, 0xCA000, 0xCC000,
+	0xCE000, 0xD0000, 0xD8000,
+	0xE0000
 };
 
 static struct hd_struct xd[XD_MAXDRIVES << 6];
@@ -138,20 +140,20 @@
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-static u_char xd_detect (u_char *controller,u_char **address)
+static u_char xd_detect (u_char *controller, unsigned int *address)
 {
 	u_char i,j,found = 0;
 
 	if (xd_override)
 	{
 		*controller = xd_type;
-		*address = NULL;
+		*address = 0;
 		return(1);
 	}
 
 	for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
 		for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
-			if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
+			if (check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
 				*controller = j;
 				*address = xd_bases[i];
 				found++;
@@ -163,11 +165,12 @@
 /* and set up the "raw" device entries in the table */
 static void xd_geninit (struct gendisk *ignored)
 {
-	u_char i,controller,*address;
+	u_char i,controller;
+	unsigned int address;
 
 	if (xd_detect(&controller,&address)) {
 
-		printk("xd_geninit: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
+		printk("xd_geninit: detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address);
 		if (controller)
 			xd_sigs[controller].init_controller(address);
 		xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
@@ -538,12 +541,12 @@
 	return (count);
 }
 
-static void xd_dtc_init_controller (u_char *address)
+static void xd_dtc_init_controller (unsigned int address)
 {
-	switch ((u_long) address) {
+	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
 		case 0xCA000:	xd_iobase = 0x324; break;
-		default:        printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
+		default:        printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
 				xd_iobase = 0x320; break;
 	}
 	xd_irq = 5;			/* the IRQ _can_ be changed on this card, but requires a hardware mod */
@@ -578,16 +581,16 @@
 		printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
 }
 
-static void xd_wd_init_controller (u_char *address)
+static void xd_wd_init_controller (unsigned int address)
 {
-	switch ((u_long) address) {
+	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
 		case 0xCA000:	xd_iobase = 0x324; break;
 		case 0xCC000:   xd_iobase = 0x328; break;
 		case 0xCE000:   xd_iobase = 0x32C; break;
 		case 0xD0000:	xd_iobase = 0x328; break;
 		case 0xD8000:	xd_iobase = 0x32C; break;
-		default:        printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
+		default:        printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
 				xd_iobase = 0x320; break;
 	}
 	xd_irq = 5;			/* don't know how to auto-detect this yet */
@@ -619,14 +622,14 @@
 		printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);	
 }
 
-static void xd_seagate_init_controller (u_char *address)
+static void xd_seagate_init_controller (unsigned int address)
 {
-	switch ((u_long) address) {
+	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
+		default:	printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
 				xd_iobase = 0x320; break;
 	}
 	xd_irq = 5;			/* the IRQ and DMA channel are fixed on the Seagate controllers */
@@ -652,14 +655,14 @@
 }
 
 /* Omti support courtesy Dirk Melchers */
-static void xd_omti_init_controller (u_char *address)
+static void xd_omti_init_controller (unsigned int address)
 {
-	switch ((u_long) address) {
+	switch (address) {
 		case 0xC8000:	xd_iobase = 0x320; break;
 		case 0xD0000:	xd_iobase = 0x324; break;
 		case 0xD8000:	xd_iobase = 0x328; break;
 		case 0xE0000:	xd_iobase = 0x32C; break;
-		default:	printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
+		default:	printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
 				xd_iobase = 0x320; break;
 	}
 	
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/block/xd.h linux/drivers/block/xd.h
--- lx2.0/v2.0.21/linux/drivers/block/xd.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/xd.h	Mon Sep 30 16:52:47 1996
@@ -0,0 +1,138 @@
+#ifndef _LINUX_XD_H
+#define _LINUX_XD_H
+
+/*
+ * This file contains the definitions for the IO ports and errors etc. for XT hard disk controllers (at least the DTC 5150X).
+ *
+ * Author: Pat Mackinlay, pat@it.com.au
+ * Date: 29/09/92
+ *
+ * Revised: 01/01/93, ...
+ *
+ * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
+ * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
+ */
+
+/* XT hard disk controller registers */
+#define XD_DATA		(xd_iobase + 0x00)	/* data RW register */
+#define XD_RESET	(xd_iobase + 0x01)	/* reset WO register */
+#define XD_STATUS	(xd_iobase + 0x01)	/* status RO register */
+#define XD_SELECT	(xd_iobase + 0x02)	/* select WO register */
+#define XD_JUMPER	(xd_iobase + 0x02)	/* jumper RO register */
+#define XD_CONTROL	(xd_iobase + 0x03)	/* DMAE/INTE WO register */
+#define XD_RESERVED	(xd_iobase + 0x03)	/* reserved */
+
+/* XT hard disk controller commands (incomplete list) */
+#define CMD_TESTREADY	0x00	/* test drive ready */
+#define CMD_RECALIBRATE	0x01	/* recalibrate drive */
+#define CMD_SENSE	0x03	/* request sense */
+#define CMD_FORMATDRV	0x04	/* format drive */
+#define CMD_VERIFY	0x05	/* read verify */
+#define CMD_FORMATTRK	0x06	/* format track */
+#define CMD_FORMATBAD	0x07	/* format bad track */
+#define CMD_READ	0x08	/* read */
+#define CMD_WRITE	0x0A	/* write */
+#define CMD_SEEK	0x0B	/* seek */
+
+/* Controller specific commands */
+#define CMD_DTCSETPARAM	0x0C	/* set drive parameters (DTC 5150X only?) */
+#define CMD_DTCGETECC	0x0D	/* get ecc error length (DTC 5150X only?) */
+#define CMD_DTCREADBUF	0x0E	/* read sector buffer (DTC 5150X only?) */
+#define CMD_DTCWRITEBUF 0x0F	/* write sector buffer (DTC 5150X only?) */
+#define CMD_DTCREMAPTRK	0x11	/* assign alternate track (DTC 5150X only?) */
+#define CMD_DTCGETPARAM	0xFB	/* get drive parameters (DTC 5150X only?) */
+#define CMD_DTCSETSTEP	0xFC	/* set step rate (DTC 5150X only?) */
+#define CMD_DTCSETGEOM	0xFE	/* set geometry data (DTC 5150X only?) */
+#define CMD_DTCGETGEOM	0xFF	/* get geometry data (DTC 5150X only?) */
+#define CMD_ST11GETGEOM 0xF8	/* get geometry data (Seagate ST11R/M only?) */
+#define CMD_WDSETPARAM	0x0C	/* set drive parameters (WD 1004A27X only?) */
+
+/* Bits for command status byte */
+#define CSB_ERROR	0x02	/* error */
+#define CSB_LUN		0x20	/* logical Unit Number */
+
+/* XT hard disk controller status bits */
+#define STAT_READY	0x01	/* controller is ready */
+#define STAT_INPUT	0x02	/* data flowing from controller to host */
+#define STAT_COMMAND	0x04	/* controller in command phase */
+#define STAT_SELECT	0x08	/* controller is selected */
+#define STAT_REQUEST	0x10	/* controller requesting data */
+#define STAT_INTERRUPT	0x20	/* controller requesting interrupt */
+
+/* XT hard disk controller control bits */
+#define PIO_MODE	0x00	/* control bits to set for PIO */
+#define DMA_MODE	0x03	/* control bits to set for DMA & interrupt */
+
+#define XD_MAXDRIVES	2	/* maximum 2 drives */
+#define XD_TIMEOUT	HZ	/* 1 second timeout */
+#define XD_RETRIES	4	/* maximum 4 retries */
+
+#undef DEBUG			/* define for debugging output */
+
+#ifdef DEBUG
+	#define DEBUG_STARTUP	/* debug driver initialisation */
+	#define DEBUG_OVERRIDE	/* debug override geometry detection */
+	#define DEBUG_READWRITE	/* debug each read/write command */
+	#define DEBUG_OTHER	/* debug misc. interrupt/DMA stuff */
+	#define DEBUG_COMMAND	/* debug each controller command */
+#endif /* DEBUG */
+
+/* this structure defines the XT drives and their types */
+typedef struct {
+	u_char heads;
+	u_short cylinders;
+	u_char sectors;
+	u_char control;
+} XD_INFO;
+
+#define	HDIO_GETGEO	0x0301		/* get drive geometry */
+
+/* this structure is returned to the HDIO_GETGEO ioctl */
+typedef struct {
+	__u8 heads;
+	__u8 sectors;
+	__u8 cylinders;
+	__u32 start;
+} XD_GEOMETRY;
+
+/* this structure defines a ROM BIOS signature */
+typedef struct {
+	unsigned int offset;
+	const char *string;
+	void (*init_controller)(unsigned int address);
+	void (*init_drive)(u_char drive);
+	const char *name;
+} XD_SIGNATURE;
+
+void xd_setup (char *command,int *integers);
+static u_char xd_detect (u_char *controller, unsigned int *address);
+static u_char xd_initdrives (void (*init_drive)(u_char drive));
+static void xd_geninit (struct gendisk *);
+
+static int xd_open (struct inode *inode,struct file *file);
+static void do_xd_request (void);
+static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
+static void xd_release (struct inode *inode,struct file *file);
+static int xd_reread_partitions (kdev_t dev);
+static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
+static void xd_recalibrate (u_char drive);
+
+static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
+static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
+static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
+static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
+static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
+
+/* card specific setup and geometry gathering code */
+static void xd_dtc_init_controller (unsigned int address);
+static void xd_dtc_init_drive (u_char drive);
+static void xd_wd_init_controller (unsigned int address);
+static void xd_wd_init_drive (u_char drive);
+static void xd_seagate_init_controller (unsigned int address);
+static void xd_seagate_init_drive (u_char drive);
+static void xd_omti_init_controller (unsigned int address);
+static void xd_omti_init_drive (u_char drive);
+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);
+static void xd_override_init_drive (u_char drive);
+
+#endif /* _LINUX_XD_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- lx2.0/v2.0.21/linux/drivers/cdrom/sbpcd.c	Mon Sep  2 15:18:26 1996
+++ linux/drivers/cdrom/sbpcd.c	Wed Sep 25 12:20:42 1996
@@ -327,6 +327,8 @@
 #include <linux/ioport.h>
 #include <linux/major.h> 
 #include <linux/string.h>
+#include <linux/vmalloc.h>
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- lx2.0/v2.0.21/linux/drivers/char/apm_bios.c	Wed May 15 09:06:55 1996
+++ linux/drivers/char/apm_bios.c	Mon Sep 30 10:31:28 1996
@@ -305,7 +305,7 @@
 
 static int	do_open(struct inode *, struct file *);
 static void	do_release(struct inode *, struct file *);
-static int	do_read(struct inode *, struct file *, char *, int);
+static long	do_read(struct inode *, struct file *, char *, unsigned long);
 static int	do_select(struct inode *, struct file *, int,
 			  select_table *);
 static int	do_ioctl(struct inode *, struct file *, u_int, u_long);
@@ -817,7 +817,8 @@
 	return 0;
 }
 
-static int do_read(struct inode *inode, struct file *fp, char *buf, int count)
+static long do_read(struct inode *inode, struct file *fp,
+	char *buf, unsigned long count)
 {
 	struct apm_bios_struct *	as;
 	int			i;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- lx2.0/v2.0.21/linux/drivers/char/atixlmouse.c	Tue Apr  2 08:43:06 1996
+++ linux/drivers/char/atixlmouse.c	Mon Sep 30 10:50:59 1996
@@ -134,12 +134,14 @@
 }
 
 
-static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
+static long write_mouse(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
 {
 	return -EINVAL;
 }
 
-static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+static long read_mouse(struct inode * inode, struct file * file,
+	char * buffer, unsigned long count)
 {
 	int i;
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- lx2.0/v2.0.21/linux/drivers/char/busmouse.c	Tue Apr  2 08:43:06 1996
+++ linux/drivers/char/busmouse.c	Mon Sep 30 10:51:46 1996
@@ -155,7 +155,8 @@
  * writes are disallowed
  */
 
-static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
+static long write_mouse(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
 {
 	return -EINVAL;
 }
@@ -164,7 +165,8 @@
  * read mouse data.  Currently never blocks.
  */
 
-static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+static long read_mouse(struct inode * inode, struct file * file,
+	char * buffer, unsigned long count)
 {
 	int r;
 	int dx;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- lx2.0/v2.0.21/linux/drivers/char/cyclades.c	Mon Aug  5 10:13:51 1996
+++ linux/drivers/char/cyclades.c	Wed Sep 25 11:52:45 1996
@@ -30,7 +30,7 @@
  * remove unused diagnostic statements; minor 0 is first;
  *
  * Revision 1.36.3.6  1996/03/13 13:21:17  marcio
- * The kernel function vremap (available only in later 1.3.xx kernels)
+ * The kernel function ioremap (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).
@@ -3083,7 +3083,7 @@
 		cy_pci_address &= 0xfffffff0;
 		if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */
 			cy_pci_address =
-			    (unsigned int) vremap(cy_pci_address,0x4000);
+			    (unsigned int) ioremap(cy_pci_address,0x4000);
 		}
 		cy_pci_io  &= 0xfffffffc;
 		cy_pci_nchan = 4 * cy_init_card((unsigned char *)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c
--- lx2.0/v2.0.21/linux/drivers/char/ftape/kernel-interface.c	Fri May 31 13:54:08 1996
+++ linux/drivers/char/ftape/kernel-interface.c	Mon Sep 30 10:43:38 1996
@@ -61,10 +61,10 @@
 static void ftape_close(struct inode *ino, struct file *filep);
 static int ftape_ioctl(struct inode *ino, struct file *filep,
 		       unsigned int command, unsigned long arg);
-static int ftape_read(struct inode *ino, struct file *fp, char *buff,
-		      int req_len);
-static int ftape_write(struct inode *ino, struct file *fp, const char *buff,
-		       int req_len);
+static long ftape_read(struct inode *ino, struct file *fp,
+		       char *buff, unsigned long req_len);
+static long ftape_write(struct inode *ino, struct file *fp,
+			const char *buff, unsigned long req_len);
 
 static struct file_operations ftape_cdev =
 {
@@ -310,13 +310,14 @@
 
 /*      Read from tape device
  */
-static int ftape_read(struct inode *ino, struct file *fp, char *buff, int req_len)
+static long ftape_read(struct inode *ino, struct file *fp,
+	char *buff, unsigned long req_len)
 {
 	TRACE_FUN(5, "ftape_read");
 	int result = -EIO;
 	int old_sigmask;
 
-	TRACEi(5, "called with count:", req_len);
+	TRACEi(5, "called with count:", (int) req_len);
 	if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit || ftape_failure) {
 		TRACE(1, "failed: not busy, failure or wrong unit");
 		TRACE_EXIT;
@@ -333,13 +334,14 @@
 
 /*      Write to tape device
  */
-static int ftape_write(struct inode *ino, struct file *fp, const char *buff, int req_len)
+static long ftape_write(struct inode *ino, struct file *fp,
+	const char *buff, unsigned long req_len)
 {
 	TRACE_FUN(8, "ftape_write");
 	int result = -EIO;
 	int old_sigmask;
 
-	TRACEi(5, "called with count:", req_len);
+	TRACEi(5, "called with count:", (int) req_len);
 	if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit || ftape_failure) {
 		TRACE(1, "failed: not busy, failure or wrong unit");
 		TRACE_EXIT;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- lx2.0/v2.0.21/linux/drivers/char/istallion.c	Mon May  6 12:26:05 1996
+++ linux/drivers/char/istallion.c	Mon Sep 30 10:50:06 1996
@@ -538,8 +538,8 @@
 static int	stli_findeisabrds(void);
 static int	stli_initports(stlibrd_t *brdp);
 static int	stli_startbrd(stlibrd_t *brdp);
-static int	stli_memread(struct inode *ip, struct file *fp, char *buf, int count);
-static int	stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int count);
+static long	stli_memread(struct inode *ip, struct file *fp, char *buf, unsigned long count);
+static long	stli_memwrite(struct inode *ip, struct file *fp, const char *buf, unsigned long count);
 static int	stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static void	stli_poll(unsigned long arg);
 static int	stli_hostcmd(stlibrd_t *brdp, int channr);
@@ -721,7 +721,7 @@
 		}
 
 		if (brdp->memaddr >= 0x100000)
-			vfree(brdp->membase);
+			iounmap(brdp->membase);
 		if ((brdp->brdtype == BRD_ECP) || (brdp->brdtype == BRD_ECPE) || (brdp->brdtype == BRD_ECPMC))
 			release_region(brdp->iobase, ECP_IOSIZE);
 		else
@@ -3394,7 +3394,7 @@
 	EBRDINIT(brdp);
 
 	if (brdp->memaddr > 0x100000) {
-		brdp->membase = vremap(brdp->memaddr, brdp->memsize);
+		brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3550,7 +3550,7 @@
 	EBRDINIT(brdp);
 
 	if (brdp->memaddr > 0x100000) {
-		brdp->membase = vremap(brdp->memaddr, brdp->memsize);
+		brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3815,7 +3815,7 @@
 		brdp->memaddr = stli_eisamemprobeaddrs[i];
 		brdp->membase = (void *) brdp->memaddr;
 		if (brdp->memaddr > 0x100000) {
-			brdp->membase = vremap(brdp->memaddr, brdp->memsize);
+			brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
 			if (brdp->membase == (void *) NULL)
 				continue;
 		}
@@ -3832,7 +3832,7 @@
 				foundit = 1;
 		}
 		if (brdp->memaddr >= 0x100000)
-			vfree(brdp->membase);
+			iounmap(brdp->membase);
 		if (foundit)
 			break;
 	}
@@ -4045,7 +4045,8 @@
  *	the slave image (and debugging :-)
  */
 
-static int stli_memread(struct inode *ip, struct file *fp, char *buf, int count)
+static long stli_memread(struct inode *ip, struct file *fp,
+	char *buf, unsigned long count)
 {
 	unsigned long	flags;
 	void		*memptr;
@@ -4053,7 +4054,7 @@
 	int		brdnr, size, n;
 
 #if DEBUG
-	printk("stli_memread(ip=%x,fp=%x,buf=%x,count=%d)\n", (int) ip, (int) fp, (int) buf, count);
+	printk("stli_memread(ip=%x,fp=%x,buf=%x,count=%lu)\n", (int) ip, (int) fp, (int) buf, count);
 #endif
 
 	brdnr = MINOR(ip->i_rdev);
@@ -4094,7 +4095,8 @@
  *	the slave image (and debugging :-)
  */
 
-static int stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int count)
+static long stli_memwrite(struct inode *ip, struct file *fp,
+	const char *buf, unsigned long count)
 {
 	unsigned long	flags;
 	void		*memptr;
@@ -4103,7 +4105,7 @@
 	int		brdnr, size, n;
 
 #if DEBUG
-	printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%x)\n", (int) ip, (int) fp, (int) buf, count);
+	printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%lx)\n", (int) ip, (int) fp, (int) buf, count);
 #endif
 
 	brdnr = MINOR(ip->i_rdev);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- lx2.0/v2.0.21/linux/drivers/char/lp.c	Tue Jul  2 19:08:41 1996
+++ linux/drivers/char/lp.c	Mon Sep 30 10:52:46 1996
@@ -295,7 +295,8 @@
 	return temp-buf;
 }
 
-static int lp_write(struct inode * inode, struct file * file, const char * buf, int count)
+static long lp_write(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	unsigned int minor = MINOR(inode->i_rdev);
 
@@ -309,8 +310,8 @@
 		return lp_write_polled(minor, buf, count);
 }
 
-static int lp_lseek(struct inode * inode, struct file * file,
-		    off_t offset, int origin)
+static long long lp_lseek(struct inode * inode, struct file * file,
+			  long long offset, int origin)
 {
 	return -ESPIPE;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- lx2.0/v2.0.21/linux/drivers/char/mem.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/char/mem.c	Sat Sep 28 23:14:21 1996
@@ -15,6 +15,7 @@
 #include <linux/tpqic02.h>
 #include <linux/ftape.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/random.h>
@@ -33,31 +34,35 @@
 void pcwatchdog_init(void);
 #endif
 
-static int read_ram(struct inode * inode, struct file * file, char * buf, int count)
+static long read_ram(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	return -EIO;
 }
 
-static int write_ram(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_ram(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	return -EIO;
 }
 
-static int read_mem(struct inode * inode, struct file * file, char * buf, int count)
+static long read_mem(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
+	unsigned long end_mem;
 	int read;
 
-	p += PAGE_OFFSET;
 	if (count < 0)
 		return -EINVAL;
-	if (MAP_NR(p) >= MAP_NR(high_memory))
+	end_mem = __pa(high_memory);
+	if (p >= end_mem)
 		return 0;
-	if (count > high_memory - p)
-		count = high_memory - p;
+	if (count > end_mem - p)
+		count = end_mem - p;
 	read = 0;
-#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
-	while (p < PAGE_OFFSET + PAGE_SIZE && count > 0) {
+#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+	while (p < PAGE_SIZE && count > 0) {
 		put_user(0,buf);
 		buf++;
 		p++;
@@ -65,27 +70,29 @@
 		read++;
 	}
 #endif
-	memcpy_tofs(buf, (void *) p, count);
+	memcpy_tofs(buf, __va(p), count);
 	read += count;
 	file->f_pos += read;
 	return read;
 }
 
-static int write_mem(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_mem(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
+	unsigned long end_mem;
 	int written;
 
-	p += PAGE_OFFSET;
 	if (count < 0)
 		return -EINVAL;
-	if (MAP_NR(p) >= MAP_NR(high_memory))
+	end_mem = __pa(high_memory);
+	if (p >= end_mem)
 		return 0;
-	if (count > high_memory - p)
-		count = high_memory - p;
+	if (count > end_mem - p)
+		count = end_mem - p;
 	written = 0;
-#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */
-	while (PAGE_OFFSET + p < PAGE_SIZE && count > 0) {
+#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */
+	while (p < PAGE_SIZE && count > 0) {
 		/* Hmm. Do something? */
 		buf++;
 		p++;
@@ -93,7 +100,7 @@
 		written++;
 	}
 #endif
-	memcpy_fromfs((void *) p, buf, count);
+	memcpy_fromfs(__va(p), buf, count);
 	written += count;
 	file->f_pos += written;
 	return count;
@@ -101,7 +108,10 @@
 
 static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
-	if (vma->vm_offset & ~PAGE_MASK)
+	unsigned long offset = vma->vm_offset;
+
+	
+	if (offset & ~PAGE_MASK)
 		return -ENXIO;
 #if defined(__i386__)
 	/*
@@ -110,17 +120,18 @@
 	 * The surround logic should disable caching for the high device
 	 * addresses anyway, but right now this seems still needed.
 	 */
-	if (x86 > 3 && vma->vm_offset >= high_memory)
+	if (x86 > 3 && offset >= __pa(high_memory))
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #endif
-	if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
+	if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	vma->vm_inode = inode;
 	inode->i_count++;
 	return 0;
 }
 
-static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
+static long read_kmem(struct inode *inode, struct file *file,
+	char *buf, unsigned long count)
 {
 	int read1, read2;
 
@@ -134,7 +145,8 @@
 	return read1 + read2;
 }
 
-static int read_port(struct inode * inode, struct file * file,char * buf, int count)
+static long read_port(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	unsigned int i = file->f_pos;
 	char * tmp = buf;
@@ -148,7 +160,8 @@
 	return tmp-buf;
 }
 
-static int write_port(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_port(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	unsigned int i = file->f_pos;
 	const char * tmp = buf;
@@ -162,17 +175,20 @@
 	return tmp-buf;
 }
 
-static int read_null(struct inode * node, struct file * file, char * buf, int count)
+static long read_null(struct inode * node, struct file * file,
+	char * buf, unsigned long count)
 {
 	return 0;
 }
 
-static int write_null(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_null(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	return count;
 }
 
-static int read_zero(struct inode * node, struct file * file, char * buf, int count)
+static long read_zero(struct inode * node, struct file * file,
+	char * buf, unsigned long count)
 {
 	int left;
 
@@ -194,13 +210,15 @@
 	return 0;
 }
 
-static int read_full(struct inode * node, struct file * file, char * buf,int count)
+static long read_full(struct inode * node, struct file * file,
+	char * buf, unsigned long count)
 {
 	file->f_pos += count;
 	return count;
 }
 
-static int write_full(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_full(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	return -ENOSPC;
 }
@@ -210,7 +228,8 @@
  * both devices with "a" now.  This was previously impossible.  SRB.
  */
 
-static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+static long long null_lseek(struct inode * inode, struct file * file,
+	long long offset, int orig)
 {
 	return file->f_pos=0;
 }
@@ -222,7 +241,8 @@
  * also note that seeking relative to the "end of file" isn't supported:
  * it has no meaning, so it returns -EINVAL.
  */
-static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+static long long memory_lseek(struct inode * inode, struct file * file,
+	long long offset, int orig)
 {
 	switch (orig) {
 		case 0:
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- lx2.0/v2.0.21/linux/drivers/char/msbusmouse.c	Fri May 10 07:44:05 1996
+++ linux/drivers/char/msbusmouse.c	Mon Sep 30 10:53:25 1996
@@ -127,12 +127,14 @@
 }
 
 
-static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
+static long write_mouse(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
 {
 	return -EINVAL;
 }
 
-static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+static long read_mouse(struct inode * inode, struct file * file,
+	char * buffer, unsigned long count)
 {
 	int i, dx, dy;
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- lx2.0/v2.0.21/linux/drivers/char/psaux.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/char/psaux.c	Mon Sep 30 10:54:26 1996
@@ -388,11 +388,12 @@
  * Write to the aux device.
  */
 
-static int write_aux(struct inode * inode, struct file * file, const char * buffer, int count)
+static long write_aux(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
 {
 	int retval = 0;
 
-	if (count > 0) {
+	if (count) {
 		int written = 0;
 
 		/* disable kbd bh to avoid mixing of cmd bytes */
@@ -425,7 +426,8 @@
  * Write to the 82C710 mouse device.
  */
 
-static int write_qp(struct inode * inode, struct file * file, const char * buffer, int count)
+static long write_qp(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
 {
 	int i = count;
 
@@ -444,7 +446,8 @@
  * Put bytes from input queue to buffer.
  */
 
-static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
+static long read_aux(struct inode * inode, struct file * file,
+	char * buffer, unsigned long count)
 {
 	struct wait_queue wait = { current, NULL };
 	int i = count;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- lx2.0/v2.0.21/linux/drivers/char/pty.c	Wed Jul 17 15:10:03 1996
+++ linux/drivers/char/pty.c	Sat Sep 28 22:58:22 1996
@@ -181,66 +181,41 @@
 
 int pty_open(struct tty_struct *tty, struct file * filp)
 {
-#if PTY_SLAVE_WAITS_ON_OPEN
-	struct wait_queue wait = { current, NULL };
-#endif
 	int	retval;
 	int	line;
 	struct	pty_struct *pty;
-	
+
+	retval = -ENODEV;
 	if (!tty || !tty->link)
-		return -ENODEV;
+		goto out;
 	line = MINOR(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PTYS))
-		return -ENODEV;
+		goto out;
 	pty = pty_state + line;
 	tty->driver_data = pty;
 
 	if (!tmp_buf) {
-		unsigned long page = get_free_page(GFP_KERNEL);
+		unsigned long page = __get_free_page(GFP_KERNEL);
 		if (!tmp_buf) {
+			retval = -ENOMEM;
 			if (!page)
-				return -ENOMEM;
+				goto out;
 			tmp_buf = (unsigned char *) page;
+			memset((void *) page, 0, PAGE_SIZE);
 		} else
 			free_page(page);
 	}
+	retval = -EIO;
+	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+		goto out;
+	if (tty->link->count != 1)
+		goto out;
 
 	clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	wake_up_interruptible(&pty->open_wait);
 	set_bit(TTY_THROTTLED, &tty->flags);
-	if (filp->f_flags & O_NDELAY)
-		return 0;
-	/*
-	 * If we're opening the master pty, just return.  If we're
-	 * trying to open the slave pty, then we have to wait for the
-	 * master pty to open.
-	 */
-	if (tty->driver.subtype == PTY_TYPE_MASTER)
-		return 0;
 	retval = 0;
-#if PTY_SLAVE_WAITS_ON_OPEN
-	add_wait_queue(&pty->open_wait, &wait);
-	while (1) {
-		if (current->signal & ~current->blocked) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		/*
-		 * Block until the master is open...
-		 */
-		current->state = TASK_INTERRUPTIBLE;
-		if (tty->link->count &&
-		    !test_bit(TTY_OTHER_CLOSED, &tty->flags))
-			break;
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&pty->open_wait, &wait);
-#else
-	if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags))
-		retval = -EPERM;
-#endif
+out:
 	return retval;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/random.c linux/drivers/char/random.c
--- lx2.0/v2.0.21/linux/drivers/char/random.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/char/random.c	Sat Sep 28 23:19:48 1996
@@ -328,14 +328,14 @@
 static struct timer_rand_state *blkdev_timer_state[MAX_BLKDEV];
 static struct wait_queue *random_wait;
 
-static int random_read(struct inode * inode, struct file * file,
-		       char * buf, int nbytes);
-static int random_read_unlimited(struct inode * inode, struct file * file,
-				 char * buf, int nbytes);
+static long random_read(struct inode * inode, struct file * file,
+		       char * buf, unsigned long nbytes);
+static long random_read_unlimited(struct inode * inode, struct file * file,
+				 char * buf, unsigned long nbytes);
 static int random_select(struct inode *inode, struct file *file,
 			 int sel_type, select_table * wait);
-static int random_write(struct inode * inode, struct file * file,
-			const char * buffer, int count);
+static long random_write(struct inode * inode, struct file * file,
+			const char * buffer, unsigned long count);
 static int random_ioctl(struct inode * inode, struct file * file,
 			unsigned int cmd, unsigned long arg);
 
@@ -1022,8 +1022,8 @@
 	extract_entropy(&random_state, (char *) buf, nbytes, 0);
 }
 
-static int
-random_read(struct inode * inode, struct file * file, char * buf, int nbytes)
+static long
+random_read(struct inode * inode, struct file * file, char * buf, unsigned long nbytes)
 {
 	struct wait_queue 	wait = { current, NULL };
 	int			n;
@@ -1079,9 +1079,9 @@
 	return (count ? count : retval);
 }
 
-static int
+static long
 random_read_unlimited(struct inode * inode, struct file * file,
-		      char * buf, int nbytes)
+		      char * buf, unsigned long nbytes)
 {
 	return extract_entropy(&random_state, buf, nbytes, 1);
 }
@@ -1105,20 +1105,13 @@
 	return 0;
 }
 
-static int
+static long
 random_write(struct inode * inode, struct file * file,
-	     const char * buffer, int count)
+	     const char * buffer, unsigned long count)
 {
 	int i;
 	__u32 word, *p;
 
-	if (count < 0)
-		return -EINVAL;
-
-	i = verify_area(VERIFY_READ, (void *) buffer, count);
-	if (i)
-		return i;
-
 	for (i = count, p = (__u32 *)buffer;
 	     i >= sizeof(__u32);
 	     i-= sizeof(__u32), p++) {
@@ -1230,6 +1223,9 @@
 		if (ent_count < 0)
 			return -EINVAL;
 		size = get_user(p++);
+		retval = verify_area(VERIFY_READ, (void *) p, size);
+		if (retval)
+			return retval;
 		retval = random_write(0, file, (const char *) p, size);
 		if (retval < 0)
 			return retval;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- lx2.0/v2.0.21/linux/drivers/char/selection.h	Thu Jul 25 20:28:05 1996
+++ linux/drivers/char/selection.h	Mon Sep 30 11:20:42 1996
@@ -108,8 +108,6 @@
  *
  */ 
 
-#ifdef __alpha__
-
 #include <asm/io.h> 
 
 /*
@@ -147,33 +145,6 @@
 	return readw((unsigned long) addr);
 }
 
-#else /* __alpha__ */
-/*
- * normal VGA console access
- * 
- * NOTE: these do normal PC-style frame buffer accesses
- */
-static inline void scr_writeb(unsigned char val, unsigned char * addr)
-{
-	*addr = val;
-}
-
-static inline unsigned char scr_readb(unsigned char * addr)
-{
-	return *addr;
-}
-
-static inline void scr_writew(unsigned short val, unsigned short * addr)
-{
-	*addr = val;
-}
-
-static inline unsigned short scr_readw(unsigned short * addr)
-{
-	return *addr;
-}
-
-#endif /* __alpha__ */
 #endif /* CONFIG_TGA_CONSOLE */
 
 static inline void memsetw(void * s, unsigned short c, unsigned int count)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- lx2.0/v2.0.21/linux/drivers/char/tpqic02.c	Fri Mar  1 07:50:41 1996
+++ linux/drivers/char/tpqic02.c	Mon Sep 30 10:38:10 1996
@@ -1878,7 +1878,8 @@
 } /* qic02_tape_interrupt */
 
 
-static int qic02_tape_lseek(struct inode * inode, struct file * file, off_t offset, int origin)
+static long long qic02_tape_lseek(struct inode * inode, struct file * file,
+	long long offset, int origin)
 {
 	return -EINVAL;	/* not supported */
 } /* qic02_tape_lseek */
@@ -1916,7 +1917,8 @@
  * request would return the EOF flag for the previous file.
  */
 
-static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long qic02_tape_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	int error;
 	kdev_t dev = inode->i_rdev;
@@ -1931,7 +1933,7 @@
 
 	if (TP_DIAGS(current_tape_dev))
 		/* can't print a ``long long'' (for filp->f_pos), so chop it */
-		printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
+		printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
 			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* Only allow mod 512 bytes at a time. */
@@ -1953,7 +1955,7 @@
 	/* This is rather ugly because it has to implement a finite state
 	 * machine in order to handle the EOF situations properly.
 	 */
-	while (count>=0) {
+	while ((signed)count>=0) {
 		bytes_done = 0;
 		/* see how much fits in the kernel buffer */
 		bytes_todo = TPQBUF_SIZE;
@@ -2091,7 +2093,8 @@
  * tape device again. The driver will detect an exception status in (No Cartridge)
  * and force a rewind. After that tar may continue writing.
  */
-static int qic02_tape_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long qic02_tape_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	int error;
 	kdev_t dev = inode->i_rdev;
@@ -2105,7 +2108,7 @@
 
 	if (TP_DIAGS(current_tape_dev))
 		/* can't print a ``long long'' (for filp->f_pos), so chop it */
-		printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
+		printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n",
 			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* only allow mod 512 bytes at a time */
@@ -2135,7 +2138,7 @@
 	if (doing_read == YES)
 		terminate_read(0);
 
-	while (count>=0) {
+	while ((signed)count>=0) {
 		/* see how much fits in the kernel buffer */
 		bytes_done = 0;
 		bytes_todo = TPQBUF_SIZE;
@@ -2226,7 +2229,7 @@
 	}
 	tpqputs(TPQD_ALWAYS, "write request for <0 bytes");
 	if (TPQDBG(DEBUG))
-		printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %x\n", status_bytes_wr, buf, total_bytes_done, count);
+		printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %lx\n", status_bytes_wr, buf, total_bytes_done, count);
 	return -EINVAL;
 } /* qic02_tape_write */
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- lx2.0/v2.0.21/linux/drivers/char/tty_io.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/char/tty_io.c	Sat Sep 28 23:07:54 1996
@@ -110,8 +110,8 @@
 
 static void initialize_tty_struct(struct tty_struct *tty);
 
-static int tty_read(struct inode *, struct file *, char *, int);
-static int tty_write(struct inode *, struct file *, const char *, int);
+static long tty_read(struct inode *, struct file *, char *, unsigned long);
+static long tty_write(struct inode *, struct file *, const char *, unsigned long);
 static int tty_select(struct inode *, struct file *, int, select_table *);
 static int tty_open(struct inode *, struct file *);
 static void tty_release(struct inode *, struct file *);
@@ -312,17 +312,20 @@
 	return -ERESTARTSYS;
 }
 
-static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
+static long hung_up_tty_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	return 0;
 }
 
-static int hung_up_tty_write(struct inode * inode, struct file * file, const char * buf, int count)
+static long hung_up_tty_write(struct inode * inode,
+	struct file * file, const char * buf, unsigned long count)
 {
 	return -EIO;
 }
 
-static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+static int hung_up_tty_select(struct inode * inode, struct file * filp,
+	int sel_type, select_table * wait)
 {
 	return 1;
 }
@@ -333,7 +336,8 @@
 	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
 
-static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+static long long tty_lseek(struct inode * inode, struct file * file,
+	long long offset, int orig)
 {
 	return -ESPIPE;
 }
@@ -719,7 +723,8 @@
 	wake_up_interruptible(&tty->write_wait);
 }
 
-static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
+static long tty_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	int i;
 	struct tty_struct * tty;
@@ -747,8 +752,7 @@
 		}
 #endif
 	if (tty->ldisc.read)
-		/* XXX casts are for what kernel-wide prototypes should be. */
-		i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);
+		i = (tty->ldisc.read)(tty,file,buf,count);
 	else
 		i = -EIO;
 	if (i > 0)
@@ -771,7 +775,7 @@
 	int ret = 0, written = 0;
 
 	for (;;) {
-		unsigned int size = PAGE_SIZE*2;
+		unsigned long size = PAGE_SIZE*2;
 		if (size > count)
 			size = count;
 		ret = write(tty, file, buf, size);
@@ -796,7 +800,8 @@
 }
 
 
-static int tty_write(struct inode * inode, struct file * file, const char * buf, int count)
+static long tty_write(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
 	int is_console;
 	struct tty_struct * tty;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- lx2.0/v2.0.21/linux/drivers/char/vc_screen.c	Tue May  7 07:50:53 1996
+++ linux/drivers/char/vc_screen.c	Sat Sep 28 23:16:01 1996
@@ -36,8 +36,8 @@
 	return size;
 }
 
-static int
-vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
+static long long
+vcs_lseek(struct inode *inode, struct file *file, long long offset, int orig)
 {
 	int size = vcs_size(inode);
 
@@ -59,8 +59,8 @@
 	return file->f_pos;
 }
 
-static int
-vcs_read(struct inode *inode, struct file *file, char *buf, int count)
+static long
+vcs_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
 	unsigned int cons = MINOR(inode->i_rdev);
@@ -81,7 +81,7 @@
 		return -ENXIO;
 
 	size = vcs_size(inode);
-	if (count < 0 || p > size)
+	if (p > size)
 		return -EINVAL;
 	if (count > size - p)
 		count = size - p;
@@ -117,8 +117,8 @@
 	return read;
 }
 
-static int
-vcs_write(struct inode *inode, struct file *file, const char *buf, int count)
+static long
+vcs_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
 	unsigned int cons = MINOR(inode->i_rdev);
@@ -139,7 +139,7 @@
 		return -ENXIO;
 
 	size = vcs_size(inode);
-	if (count < 0 || p > size)
+	if (p > size)
 		return -EINVAL;
 	if (count > size - p)
 		count = size - p;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/bsd_comp.c linux/drivers/net/bsd_comp.c
--- lx2.0/v2.0.21/linux/drivers/net/bsd_comp.c	Wed Jul 17 07:17:29 1996
+++ linux/drivers/net/bsd_comp.c	Sat Sep 28 10:55:22 1996
@@ -67,6 +67,7 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/sched.h>	/* to get the struct task_struct */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- lx2.0/v2.0.21/linux/drivers/net/dgrs.c	Mon May  6 12:26:07 1996
+++ linux/drivers/net/dgrs.c	Wed Sep 25 11:50:26 1996
@@ -225,10 +225,10 @@
 	/*
 	 *	Now map the DMA registers into our virtual space
 	 */
-	priv->vplxdma = (ulong *) vremap (priv->plxdma, 256);
+	priv->vplxdma = (ulong *) ioremap (priv->plxdma, 256);
 	if (!priv->vplxdma)
 	{
-		printk("%s: can't vremap() the DMA regs", dev->name);
+		printk("%s: can't ioremap() the DMA regs", dev->name);
 		return (0);
 	}
 
@@ -835,7 +835,7 @@
 	/*
 	 * Map in the dual port memory
 	 */
-	priv->vmem = vremap(dev->mem_start, 2048*1024);
+	priv->vmem = ioremap(dev->mem_start, 2048*1024);
 	if (!priv->vmem)
 	{
 		printk("%s: cannot map in board memory\n", dev->name);
@@ -882,7 +882,7 @@
 	memcpy(priv->vmem, dgrs_code, dgrs_ncode);	/* Load code */
 	if (memcmp(priv->vmem, dgrs_code, dgrs_ncode))
 	{
-		vfree(priv->vmem);
+		iounmap(priv->vmem);
 		priv->vmem = NULL;
 		printk("%s: download compare failed\n", dev->name);
 		return -ENXIO;
@@ -1330,9 +1330,9 @@
 		proc_reset(dgrs_root_dev, 1);
 
 		if (priv->vmem)
-			vfree(priv->vmem);
+			iounmap(priv->vmem);
 		if (priv->vplxdma)
-			vfree((uchar *) priv->vplxdma);
+			iounmap((uchar *) priv->vplxdma);
 
 		release_region(dgrs_root_dev->base_addr, 256);
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/dgrs_driver.c linux/drivers/net/dgrs_driver.c
--- lx2.0/v2.0.21/linux/drivers/net/dgrs_driver.c	Mon May  6 12:26:08 1996
+++ linux/drivers/net/dgrs_driver.c	Wed Sep 25 11:51:49 1996
@@ -225,10 +225,10 @@
 	/*
 	 *	Now map the DMA registers into our virtual space
 	 */
-	priv->vplxdma = (ulong *) vremap (priv->plxdma, 256);
+	priv->vplxdma = (ulong *) ioremap (priv->plxdma, 256);
 	if (!priv->vplxdma)
 	{
-		printk("%s: can't vremap() the DMA regs", dev->name);
+		printk("%s: can't ioremap() the DMA regs", dev->name);
 		return (0);
 	}
 
@@ -835,7 +835,7 @@
 	/*
 	 * Map in the dual port memory
 	 */
-	priv->vmem = vremap(dev->mem_start, 2048*1024);
+	priv->vmem = ioremap(dev->mem_start, 2048*1024);
 	if (!priv->vmem)
 	{
 		printk("%s: cannot map in board memory\n", dev->name);
@@ -882,7 +882,7 @@
 	memcpy(priv->vmem, dgrs_code, dgrs_ncode);	/* Load code */
 	if (memcmp(priv->vmem, dgrs_code, dgrs_ncode))
 	{
-		vfree(priv->vmem);
+		iounmap(priv->vmem);
 		priv->vmem = NULL;
 		printk("%s: download compare failed\n", dev->name);
 		return -ENXIO;
@@ -1330,9 +1330,9 @@
 		proc_reset(dgrs_root_dev, 1);
 
 		if (priv->vmem)
-			vfree(priv->vmem);
+			iounmap(priv->vmem);
 		if (priv->vplxdma)
-			vfree((uchar *) priv->vplxdma);
+			iounmap((uchar *) priv->vplxdma);
 
 		release_region(dgrs_root_dev->base_addr, 256);
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- lx2.0/v2.0.21/linux/drivers/net/eexpress.c	Fri Jun  7 14:21:04 1996
+++ linux/drivers/net/eexpress.c	Sat Sep 28 22:06:12 1996
@@ -1,93 +1,72 @@
-/* $Id: eexpress.c,v 1.13 1996/05/19 15:59:51 phil Exp $
+/* Intel EtherExpress 16 device driver for Linux
  *
- * Intel EtherExpress device driver for Linux
+ * Written by John Sullivan, 1995
+ *  based on original code by Donald Becker, with changes by
+ *  Alan Cox and Pauline Middelink.
  *
- * Original version written 1993 by Donald Becker
- * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
- * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
- * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
- * More fixes by Philip Blundell <pjb27@cam.ac.uk>
+ * Many modifications, and currently maintained, by
+ *  Philip Blundell <Philip.Blundell@pobox.com>
  */
 
-/*
- * The original EtherExpress driver was just about usable, but
- * suffered from a long startup delay, a hard limit of 16k memory
- * usage on the card (EtherExpress 16s have either 32k or 64k),
- * and random locks under load. The last was particularly annoying
- * and made running eXceed/W preferable to Linux/XFree. After hacking
- * through the driver for a couple of days, I had fixed most of the
- * card handling errors, at the expense of turning the code into
- * a complete jungle, but still hadn't tracked down the lock-ups.
- * I had hoped these would be an IP bug, but failed to reproduce them
- * under other drivers, so decided to start from scratch and rewrite
- * the driver cleanly. And here it is.
+/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
+ * design using the i82586 Ethernet coprocessor.  It bears no relationship,
+ * as far as I know, to the similarly-named "EtherExpress Pro" range.
  *
- * It's still not quite there, but self-corrects a lot more problems.
- * the 'CU wedged, resetting...' message shouldn't happen at all, but
- * at least we recover. It still locks occasionally, any ideas welcome.
+ * Historically, Linux support for these cards has been very bad.  However,
+ * things seem to be getting better slowly. 
+ */
+
+/* It would be nice to seperate out all the 82586-specific code, so that it 
+ * could be shared between drivers (as with 8390.c).  But this would be quite
+ * a messy job.  The main motivation for doing this would be to bring 3c507
+ * support back up to scratch.
+ */
+
+/* If your card is confused about what sort of interface it has (eg it
+ * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
+ * or 'SOFTSET /LISA' from DOS seems to help.
+ */
+
+/* Here's the scoop on memory mapping.
  *
- * The original startup delay experienced by some people was due to the
- * first ARP request for the address of the default router getting lost.
- * (mostly the reply we were getting back was arriving before our
- * hardware address was set up, or before the configuration sequence
- * had told the card NOT to strip of the frame header). If you a long
- * startup delay, you may have lost this ARP request/reply, although
- * the original cause has been fixed. However, it is more likely that
- * you've just locked under this version.
+ * There are three ways to access EtherExpress card memory: either using the
+ * shared-memory mapping, or using PIO through the dataport, or using PIO
+ * through the "shadow memory" ports.
  *
- * The main changes are in the 586 initialization procedure (which was
- * just broken before - the EExp is a strange beasty and needs careful
- * handling) the receive buffer handling (we now use a non-terminating
- * circular list of buffers, which stops the card giving us out-of-
- * resources errors), and the transmit code. The driver is also more
- * structured, and I have tried to keep the kernel interface separate
- * from the hardware interface (although some routines naturally want
- * to do both).
+ * The shadow memory system works by having the card map some of its memory
+ * as follows:
  *
- * John Sullivan
+ * (the low five bits of the SMPTR are ignored)
+ * 
+ *  base+0x4000..400f      memory at SMPTR+0..15
+ *  base+0x8000..800f      memory at SMPTR+16..31
+ *  base+0xc000..c007      dubious stuff (memory at SMPTR+16..23 apparently)
+ *  base+0xc008..c00f      memory at 0x0008..0x000f
  *
- * 18/5/95:
+ * This last set (the one at c008) is particularly handy because the SCB 
+ * lives at 0x0008.  So that set of ports gives us easy random access to data 
+ * in the SCB without having to mess around setting up pointers and the like.
+ * We always use this method to access the SCB (via the scb_xx() functions).
  *
- * The lock-ups seem to happen when you access card memory after a 586
- * reset. This happens only 1 in 12 resets, on a random basis, and
- * completely locks the machine. As far as I can see there is no
- * workaround possible - the only thing to be done is make sure we
- * never reset the card *after* booting the kernel - once at probe time
- * must be sufficient, and we'll just have to put up with that failing
- * occasionally (or buy a new NIC). By the way, this looks like a 
- * definite card bug, since Intel's own driver for DOS does exactly the
- * same.
+ * Dataport access works by aiming the appropriate (read or write) pointer
+ * at the first address you're interested in, and then reading or writing from
+ * the dataport.  The pointers auto-increment after each transfer.  We use
+ * this for data transfer.
  *
- * This bug makes switching in and out of promiscuous mode a risky
- * business, since we must do a 586 reset each time.
+ * We don't use the shared-memory system because it allegedly doesn't work on
+ * all cards, and because it's a bit more prone to go wrong (it's one more
+ * thing to configure...).
  */
 
-/*
- * Sources:
- *
- * The original eexpress.c by Donald Becker
- *   Sources: the Crynwr EtherExpress driver source.
- *            the Intel Microcommunications Databook Vol.1 1990
- *
- * wavelan.c and i82586.h
- *   This was invaluable for the complete '586 configuration details
- *   and command format.
- *
- * The Crynwr sources (again)
- *   Not as useful as the Wavelan driver, but then I had eexpress.c to
- *   go off.
- *
- * The Intel EtherExpress 16 ethernet card
- *   Provided the only reason I want to see a working etherexpress driver.
- *   A lot of fixes came from just observing how the card (mis)behaves when
- *   you prod it.
+/* Known bugs:
  *
+ * - 8-bit mode is not supported, and makes things go wrong.
+ * - Multicast and promiscuous modes are not supported.
+ * - The card seems to want to give us two interrupts every time something
+ *   happens, where just one would be better. 
+ * - The statistics may not be getting reported properly.
  */
 
-static char version[] = 
-"eexpress.c: v0.10 04-May-95 John Sullivan <js10039@cam.ac.uk>\n"
-"            v0.14 19-May-96 Philip Blundell <phil@tazenda.demon.co.uk>\n";
-
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -102,7 +81,6 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 
@@ -111,31 +89,12 @@
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
-/*
- * Not actually used yet - may be implemented when the driver has
- * been debugged!
- *
- * Debug Level		Driver Status
- *	0		Final release
- *	1		Beta test
- *	2
- *	3
- * 	4		Report timeouts & 586 errors (normal debug level)
- *	5		Report all major events
- *	6		Dump sent/received packet contents
- *	7		Report function entry/exit
- */
-
 #ifndef NET_DEBUG
-#define NET_DEBUG 4
+#define NET_DEBUG 4 
 #endif
-static unsigned int net_debug = NET_DEBUG;
-
-#undef F_DEB
 
-#include "eth82586.h"
+#include "eexpress.h"
 
-#define PRIV(x)         ((struct net_local *)(x)->priv)
 #define EEXP_IO_EXTENT  16
 
 /*
@@ -145,14 +104,15 @@
 struct net_local 
 {
 	struct enet_statistics stats;
-	unsigned long init_time;        /* jiffies when eexp_hw_init586 called */
-	unsigned short rx_first;        /* first rx buf, same as RX_BUF_START */
-	unsigned short rx_last;         /* last rx buf */
-	unsigned short tx_head;         /* next free tx buf */
-	unsigned short tx_reap;         /* first in-use tx buf */
-	unsigned short tx_tail;         /* previous tx buf to tx_head */
-	unsigned short tx_link;         /* last known-executing tx buf */
-	unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
+	unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
+	unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
+	unsigned short rx_last;      /* last rx buf */
+	unsigned short tx_head;      /* next free tx buf */
+	unsigned short tx_reap;      /* first in-use tx buf */
+	unsigned short tx_tail;      /* previous tx buf to tx_head */
+	unsigned short tx_link;      /* last known-executing tx buf */
+	unsigned short last_tx_restart;   /* set to tx_link when we
+					     restart the CU */
 	unsigned char started;
 	unsigned char promisc;
 	unsigned short rx_buf_start;
@@ -161,45 +121,64 @@
 	unsigned short num_rx_bufs;
 };
 
-unsigned short start_code[] = {
-	0x0000,                 /* SCP: set bus to 16 bits */
-	0x0000,0x0000,          /* junk */
+/* This is the code and data that is downloaded to the EtherExpress card's
+ * memory at boot time.
+ */
+
+static unsigned short start_code[] = {
+/* 0xfff6 */
+	0x0000,                 /* set bus to 16 bits */
+	0x0000,0x0000,         
 	0x0000,0x0000,          /* address of ISCP (lo,hi) */
 
+/* 0x0000 */
 	0x0001,                 /* ISCP: busy - cleared after reset */
 	0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */
 
 	0x0000,0x0000,          /* SCB: status, commands */
-	0x0000,0x0000,          /* links to first command block, first receive descriptor */
+	0x0000,0x0000,          /* links to first command block, 
+				   first receive descriptor */
 	0x0000,0x0000,          /* CRC error, alignment error counts */
 	0x0000,0x0000,          /* out of resources, overrun error counts */
 
 	0x0000,0x0000,          /* pad */
 	0x0000,0x0000,
 
-	0x0000,Cmd_Config,      /* startup configure sequence, at 0x0020 */
+/* 0x0020 -- start of 82586 CU program */
+#define CONF_LINK 0x0020
+	0x0000,Cmd_Config,      
 	0x0032,                 /* link to next command */
 	0x080c,                 /* 12 bytes follow : fifo threshold=8 */
-	0x2e40,                 /* don't rx bad frames : SRDY/ARDY => ext. sync. : preamble len=8
-	                         * take addresses from data buffers : 6 bytes/address */
-	0x6000,                 /* default backoff method & priority : interframe spacing = 0x60 */
-	0xf200,                 /* slot time=0x200 : max collision retry = 0xf */
-	0x0000,                 /* no HDLC : normal CRC : enable broadcast : disable promiscuous/multicast modes */
+	0x2e40,                 /* don't rx bad frames
+				 * SRDY/ARDY => ext. sync. : preamble len=8
+	                         * take addresses from data buffers
+				 * 6 bytes/address
+				 */
+	0x6000,                 /* default backoff method & priority
+				 * interframe spacing = 0x60 */
+	0xf200,                 /* slot time=0x200 
+				 * max collision retry = 0xf */
+	0x0000,                 /* no HDLC : normal CRC : enable broadcast 
+				 * disable promiscuous/multicast modes */
 	0x003c,                 /* minimum frame length = 60 octets) */
 
 	0x0000,Cmd_INT|Cmd_SetAddr,
 	0x003e,                 /* link to next command */
-	0x0000,0x0000,0x0000,   /* hardware address placed here, 0x0038 */
+	0x0000,0x0000,0x0000,   /* hardware address placed here */
+
+	0x0000,Cmd_TDR,0x0048,
+/* 0x0044 -- TDR result placed here */
+	0x0000, 0x0000,
+
+/* Eventually, a set-multicast will go in here */
+
 	0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
-	0x003e,
+	0x0048,
 
 	0x0000
 
 };
 
-#define CONF_LINK 0x0020
-#define CONF_HW_ADDR 0x0038
-
 /* maps irq number to EtherExpress magic value */
 static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 
@@ -207,32 +186,79 @@
  * Prototypes for Linux interface
  */
 
-extern int                  express_probe(struct device *dev);
-static int                     eexp_open (struct device *dev);
-static int                     eexp_close(struct device *dev);
+extern int express_probe(struct device *dev);
+static int eexp_open(struct device *dev);
+static int eexp_close(struct device *dev);
 static struct enet_statistics *eexp_stats(struct device *dev);
-static int                     eexp_xmit (struct sk_buff *buf, struct device *dev);
+static int eexp_xmit(struct sk_buff *buf, struct device *dev);
 
-static void                    eexp_irq  (int irq, void *dev_addr, struct pt_regs *regs);
-static void                    eexp_set_multicast(struct device *dev);
+static void eexp_irq(int irq, void *dev_addr, struct pt_regs *regs);
+static void eexp_set_multicast(struct device *dev);
 
 /*
  * Prototypes for hardware access functions
  */
 
-static void           eexp_hw_rx        (struct device *dev);
-static void           eexp_hw_tx        (struct device *dev, unsigned short *buf, unsigned short len);
-static int            eexp_hw_probe     (struct device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location);
+static void eexp_hw_rx_pio(struct device *dev);
+static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
+		       unsigned short len);
+static int eexp_hw_probe(struct device *dev,unsigned short ioaddr);
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
+					 unsigned char location);
 
 static unsigned short eexp_hw_lasttxstat(struct device *dev);
-static void           eexp_hw_txrestart (struct device *dev);
+static void eexp_hw_txrestart(struct device *dev);
+
+static void eexp_hw_txinit    (struct device *dev);
+static void eexp_hw_rxinit    (struct device *dev);
 
-static void           eexp_hw_txinit    (struct device *dev);
-static void           eexp_hw_rxinit    (struct device *dev);
+static void eexp_hw_init586   (struct device *dev);
+
+/*
+ * Primitive hardware access functions.
+ */
+
+static inline unsigned short scb_status(struct device *dev)
+{
+	return inw(dev->base_addr + 0xc008);
+}
+
+static inline unsigned short scb_rdcmd(struct device *dev)
+{
+	return inw(dev->base_addr + 0xc00a);
+}
+
+static inline void scb_command(struct device *dev, unsigned short cmd)
+{
+	outw(cmd, dev->base_addr + 0xc00a);
+}
+
+static inline void scb_wrcbl(struct device *dev, unsigned short val)
+{
+	outw(val, dev->base_addr + 0xc00c);
+}
+
+static inline void scb_wrrfa(struct device *dev, unsigned short val)
+{
+	outw(val, dev->base_addr + 0xc00e);
+}
+
+static inline void set_loopback(struct device *dev)
+{
+	outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config); 
+}
+
+static inline void clear_loopback(struct device *dev)
+{
+	outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config); 
+}
 
-static void           eexp_hw_init586   (struct device *dev);
-static void           eexp_hw_ASICrst   (struct device *dev);
+static inline short int SHADOW(short int addr)
+{
+	addr &= 0x1f;
+	if (addr > 0xf) addr += 0x3ff0;
+	return addr + 0x4000;
+}
 
 /*
  * Linux interface
@@ -252,7 +278,7 @@
 	else if (ioaddr)
 		return ENXIO;
 
-	for ( port=&ports[0] ; *port ; port++ ) 
+	for (port=&ports[0] ; *port ; port++ ) 
 	{
 		unsigned short sum = 0;
 		int i;
@@ -285,14 +311,14 @@
 		return -ENXIO;
 
 	if (irq2dev_map[irq] ||
-	      /* more consistent, surely? */
 	   ((irq2dev_map[irq]=dev),0) ||
-	     request_irq(irq,&eexp_irq,0,"eexpress",NULL)) 
+	     request_irq(irq,&eexp_irq,0,"EtherExpress",NULL)) 
 		return -EAGAIN;
 
-	request_region(ioaddr, EEXP_IO_EXTENT, "eexpress");
+	request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress");
 	dev->tbusy = 0;
 	dev->interrupt = 0;
+
 	eexp_hw_init586(dev);
 	dev->start = 1;
 	MOD_INC_USE_COUNT;
@@ -303,25 +329,27 @@
 }
 
 /*
- * close and disable the interface, leaving
- * the 586 in reset
+ * close and disable the interface, leaving the 586 in reset.
  */
 static int eexp_close(struct device *dev)
 {
 	unsigned short ioaddr = dev->base_addr;
+	struct net_local *lp = dev->priv;
+
 	int irq = dev->irq;
 
 	dev->tbusy = 1; 
 	dev->start = 0;
   
 	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-	PRIV(dev)->started = 0;
-	outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);
+	lp->started = 0;
+	scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
 	outb(0,ioaddr+SIGNAL_CA);
 	free_irq(irq,NULL);
 	irq2dev_map[irq] = NULL;
 	outb(i586_RST,ioaddr+EEPROM_Ctrl);
 	release_region(ioaddr,16);
+
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -334,109 +362,117 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
-	/* 
-	 * Hmmm, this looks a little too easy... The card maintains
-	 * some stats in the SCB, and I'm not convinced we're
-	 * incrementing the most sensible statistics when the card
-	 * returns an error (esp. slow DMA, out-of-resources)
-	 */
 	return &lp->stats;
 }
 
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
+/* 
+ * This gets called when a higher level thinks we are broken.  Check that
+ * nothing has become jammed in the CU.
  */
 
-static int eexp_xmit(struct sk_buff *buf, struct device *dev)
+static void unstick_cu(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
-	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-	if (dev->tbusy) 
+	if (lp->started) 
 	{
-		/* This will happen, but hopefully not as often as when
-		 * tbusy==0. If it happens too much, we probably ought
-		 * to think about unwedging ourselves...
-		 */
-		if (test_bit(0,(void *)&PRIV(dev)->started)) 
+		if ((jiffies - dev->trans_start)>50) 
 		{
-			if ((jiffies - dev->trans_start)>5) 
+			if (lp->tx_link==lp->last_tx_restart) 
 			{
-				if (lp->tx_link==lp->last_tx_restart) 
+				unsigned short boguscount=200,rsst;
+				printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
+				       dev->name, scb_status(dev));
+				eexp_hw_txinit(dev);
+				lp->last_tx_restart = 0;
+				scb_wrcbl(dev, lp->tx_link);
+				scb_command(dev, SCB_CUstart);
+				outb(0,ioaddr+SIGNAL_CA);
+				while (!SCB_complete(rsst=scb_status(dev))) 
 				{
-					unsigned short boguscount=200,rsst;
-					printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
-						dev->name,inw(ioaddr+SCB_STATUS));
-					eexp_hw_txinit(dev);
-					lp->last_tx_restart = 0;
-					outw(lp->tx_link,ioaddr+SCB_CBL);
-					outw(0,ioaddr+SCB_STATUS);
-					outw(SCB_CUstart,ioaddr+SCB_CMD);
-					outb(0,ioaddr+SIGNAL_CA);
-					while (!SCB_complete(rsst=inw(ioaddr+SCB_STATUS))) 
+					if (!--boguscount) 
 					{
-						if (!--boguscount) 
-						{
-							boguscount=200;
-							printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
-								dev->name,rsst);
-							outw(lp->tx_link,ioaddr+SCB_CBL);
-							outw(0,ioaddr+SCB_STATUS);
-							outw(SCB_CUstart,ioaddr+SCB_CMD);
-							outb(0,ioaddr+SIGNAL_CA);
-						}
+						boguscount=200;
+						printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
+						       dev->name,rsst);
+						scb_wrcbl(dev, lp->tx_link);
+						scb_command(dev, SCB_CUstart);
+						outb(0,ioaddr+SIGNAL_CA);
 					}
-					dev->tbusy = 0;
-					mark_bh(NET_BH);
+				}
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+			else
+			{
+				unsigned short status = scb_status(dev);
+				if (SCB_CUdead(status)) 
+				{
+					unsigned short txstatus = eexp_hw_lasttxstat(dev);
+					printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
+					       dev->name, status, txstatus);
+					eexp_hw_txrestart(dev);
 				}
 				else
 				{
-					unsigned short status = inw(ioaddr+SCB_STATUS);
-					if (SCB_CUdead(status)) 
+					unsigned short txstatus = eexp_hw_lasttxstat(dev);
+					if (dev->tbusy && !txstatus) 
 					{
-						unsigned short txstatus = eexp_hw_lasttxstat(dev);
-						printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
-							dev->name, status, txstatus);
-						eexp_hw_txrestart(dev);
+						printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
+						       dev->name,status,txstatus);
+						eexp_hw_init586(dev); 
+						dev->tbusy = 0;
+						mark_bh(NET_BH);
 					}
 					else
 					{
-						unsigned short txstatus = eexp_hw_lasttxstat(dev);
-						if (dev->tbusy && !txstatus) 
-						{
-							printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
-								dev->name,status,txstatus);
-							eexp_hw_init586(dev); 
-							dev->tbusy = 0;
-							mark_bh(NET_BH);
-						}
+						printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
 					}
 				}
 			}
 		}
-		else
+	}
+	else
+	{
+		if ((jiffies-lp->init_time)>10)
 		{
-			if ((jiffies-lp->init_time)>10)
-			{
-				unsigned short status = inw(ioaddr+SCB_STATUS);
-				printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
-					dev->name, status);
-				eexp_hw_init586(dev);
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
+			unsigned short status = scb_status(dev);
+			printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
+			       dev->name, status);
+			eexp_hw_init586(dev);
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
 		}
 	}
+}
+
+/*
+ * Called to transmit a packet, or to allow us to right ourselves
+ * if the kernel thinks we've died.
+ */
+static int eexp_xmit(struct sk_buff *buf, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+#if NET_DEBUG > 6
+	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
+#endif
+
+	outb(SIRQ_dis|irqrmap[dev->irq],dev->base_addr+SET_IRQ);
+	
+	/* If dev->tbusy is set, all our tx buffers are full but the kernel
+	 * is calling us anyway.  Check that nothing bad is happening.
+	 */
+	if (dev->tbusy) 
+		unstick_cu(dev);
 
 	if (buf==NULL) 
 	{
-		unsigned short status = inw(ioaddr+SCB_STATUS);
+		/* Some higher layer thinks we might have missed a
+		 * tx-done interrupt.  Does this ever actually happen?
+		 */
+		unsigned short status = scb_status(dev);
 		unsigned short txstatus = eexp_hw_lasttxstat(dev);
 		if (SCB_CUdead(status)) 
 		{
@@ -446,7 +482,7 @@
 			eexp_hw_txrestart(dev);
 		}
 		dev_tint(dev);
-		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+		outb(SIRQ_en|irqrmap[dev->irq],dev->base_addr+SET_IRQ);
 		return 0;
 	}
 
@@ -456,15 +492,14 @@
 	}
 	else
 	{
-		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : ETH_ZLEN;
+		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len :
+			ETH_ZLEN;
 		unsigned short *data = (unsigned short *)buf->data;
 
-		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-		eexp_hw_tx(dev,data,length);
-		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	        eexp_hw_tx_pio(dev,data,length);
 	}
 	dev_kfree_skb(buf, FREE_WRITE);
-	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	outb(SIRQ_en|irqrmap[dev->irq],dev->base_addr+SET_IRQ);
 	return 0;
 }
 
@@ -480,72 +515,92 @@
 	struct device *dev = irq2dev_map[irq];
 	struct net_local *lp;
 	unsigned short ioaddr,status,ack_cmd;
-	unsigned short old_rp,old_wp;
 
 	if (dev==NULL) 
 	{
-		printk(KERN_WARNING "net_interrupt(): irq %d for unknown device caught by EExpress\n",irq);
+		printk(KERN_WARNING "eexpress: irq %d for unknown device\n",
+		       irq);
 		return;
 	}
 
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: interrupt\n", dev->name);
-#endif
-
-	dev->interrupt = 1; /* should this be reset on exit? */
-  
 	lp = (struct net_local *)dev->priv;
 	ioaddr = dev->base_addr;
 
-	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-	old_rp = inw(ioaddr+READ_PTR);
-	old_wp = inw(ioaddr+WRITE_PTR);
-	status = inw(ioaddr+SCB_STATUS);
+	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ); 
+
+	dev->interrupt = 1; 
+  
+	status = scb_status(dev);
+
+#if NET_DEBUG > 4
+	printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
+#endif
+
 	ack_cmd = SCB_ack(status);
 
-	if (PRIV(dev)->started==0 && SCB_complete(status)) 
+	if (lp->started==0 && SCB_complete(status)) 
 	{
+		while (SCB_CUstat(status)==2)
+				status = scb_status(dev);
 #if NET_DEBUG > 4
-		printk(KERN_DEBUG "%s: SCBcomplete event received\n", dev->name);
+		printk(KERN_DEBUG "%s: CU went non-active (status = %08x)\n",
+		       dev->name, status);
 #endif
-		while (SCB_CUstat(status)==2)
-			status = inw_p(ioaddr+SCB_STATUS);
+
+		/* now get the TDR status */
+		{
+			short tdr_status;
+			outw(0x40, dev->base_addr + SM_PTR);
+			tdr_status = inw(dev->base_addr + 0x8004);
+			if (tdr_status & TDR_SHORT) {
+					printk(KERN_WARNING "%s: TDR reports cable short at %d tick%s\n", dev->name, tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
+			} 
+			else if (tdr_status & TDR_OPEN) {
+					printk(KERN_WARNING "%s: TDR reports cable broken at %d tick%s\n", dev->name, tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
+			}
+			else if (tdr_status & TDR_XCVRPROBLEM) {
+					printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
+			}
 #if NET_DEBUG > 4
-                printk(KERN_DEBUG "%s: CU went non-active (status = %08x)\n", dev->name, status);
+			else if (tdr_status & TDR_LINKOK) {
+					printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
+			}
 #endif
-		PRIV(dev)->started=1;
-		outw_p(lp->tx_link,ioaddr+SCB_CBL);
-		outw_p(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
-		ack_cmd |= SCB_CUstart | SCB_RUstart;
+		}
+
+		lp->started=1;
+		scb_wrcbl(dev, lp->tx_link);
+		scb_wrrfa(dev, lp->rx_buf_start);
+		ack_cmd |= SCB_CUstart | SCB_RUstart | 0x2000;
 	}
-	else if (PRIV(dev)->started) 
+	else if (lp->started) 
 	{
 		unsigned short txstatus;
 		txstatus = eexp_hw_lasttxstat(dev);
 	}
-  
+
 	if (SCB_rxdframe(status)) 
 	{
-		eexp_hw_rx(dev);
+		eexp_hw_rx_pio(dev);
 	}
 
-	if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) 
+	if ((lp->started&2)!=0 && SCB_RUstat(status)!=4) 
 	{
-		printk(KERN_WARNING "%s: RU stopped status %04x, restarting...\n",
+		printk(KERN_WARNING "%s: RU stopped: status %04x\n",
 			dev->name,status);
 		lp->stats.rx_errors++;
 		eexp_hw_rxinit(dev);
-		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
+		scb_wrrfa(dev, lp->rx_buf_start);
 		ack_cmd |= SCB_RUstart;
 	} 
-	else if (PRIV(dev)->started==1 && SCB_RUstat(status)==4) 
-		PRIV(dev)->started|=2;
+	else if (lp->started==1 && SCB_RUstat(status)==4) 
+		lp->started|=2;
 
-	outw(ack_cmd,ioaddr+SCB_CMD);
+	scb_command(dev, ack_cmd);
 	outb(0,ioaddr+SIGNAL_CA);
-	outw(old_rp,ioaddr+READ_PTR);
-	outw(old_wp,ioaddr+WRITE_PTR);
-	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+
+	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); 
+
 	dev->interrupt = 0;
 #if NET_DEBUG > 6
         printk(KERN_DEBUG "%s: leaving eexp_irq()\n", dev->name);
@@ -560,42 +615,44 @@
 /*
  * Check all the receive buffers, and hand any received packets
  * to the upper levels. Basic sanity check on each frame
- * descriptor
+ * descriptor, though we don't bother trying to fix broken ones.
  */
  
-static void eexp_hw_rx(struct device *dev)
+static void eexp_hw_rx_pio(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
-	unsigned short old_rp = inw(ioaddr+READ_PTR);
 	unsigned short rx_block = lp->rx_first;
 	unsigned short boguscount = lp->num_rx_bufs;
+	unsigned short ioaddr = dev->base_addr;
 
 #if NET_DEBUG > 6
 	printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
 #endif
 
-	while (outw(rx_block,ioaddr+READ_PTR),boguscount--) 
+	while (boguscount--) 
 	{
-		unsigned short status = inw(ioaddr);
-		unsigned short rfd_cmd = inw(ioaddr);
-		unsigned short rx_next = inw(ioaddr);
-		unsigned short pbuf = inw(ioaddr);
-		unsigned short pkt_len;
+		unsigned short status, rfd_cmd, rx_next, pbuf, pkt_len;
+
+		outw(rx_block, ioaddr + READ_PTR);
+		status = inw(ioaddr + DATAPORT);
+		rfd_cmd = inw(ioaddr + DATAPORT);
+		rx_next = inw(ioaddr + DATAPORT);
+		pbuf = inw(ioaddr + DATAPORT);
 
 		if (FD_Done(status)) 
 		{
-			outw(pbuf,ioaddr+READ_PTR);
-			pkt_len = inw(ioaddr);
+			outw(pbuf, ioaddr + READ_PTR);
+			pkt_len = inw(ioaddr + DATAPORT);
 
 			if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16
 				|| (pkt_len & 0xc000)!=0xc000) 
 			{
+				/* This should never happen.  If it does,
+				 * we almost certainly have a driver bug.
+				 */
 				printk(KERN_WARNING "%s: Rx frame at %04x corrupted, status %04x, cmd %04x, "
 					"next %04x, pbuf %04x, len %04x\n",dev->name,rx_block,
 					status,rfd_cmd,rx_next,pbuf,pkt_len);
-				boguscount++;
 				continue;
 			}
 			else if (!FD_OK(status)) 
@@ -625,50 +682,54 @@
 				}
 				skb->dev = dev;
 				skb_reserve(skb, 2);
-				outw(pbuf+10,ioaddr+READ_PTR);
-				insw(ioaddr,skb_put(skb,pkt_len),(pkt_len+1)>>1);
+				outw(pbuf+10, ioaddr+READ_PTR);
+			        insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
 				skb->protocol = eth_type_trans(skb,dev);
 				netif_rx(skb);
 				lp->stats.rx_packets++;
 			}
-			outw(rx_block,ioaddr+WRITE_PTR);
-			outw(0x0000,ioaddr);
-			outw(0x0000,ioaddr);
+			outw(rx_block, ioaddr+WRITE_PTR);
+			outw(0, ioaddr+DATAPORT);
+			outw(0, ioaddr+DATAPORT);
 		}
 		rx_block = rx_next;
 	}
-	outw(old_rp,ioaddr+READ_PTR);
-	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
 /*
  * Hand a packet to the card for transmission
  * If we get here, we MUST have already checked
  * to make sure there is room in the transmit
- * buffer region
+ * buffer region.
  */
 
-static void eexp_hw_tx(struct device *dev, unsigned short *buf, unsigned short len)
+static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
+		       unsigned short len)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
-	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 
-	outw(lp->tx_head,ioaddr+WRITE_PTR);
-	outw(0x0000,ioaddr);
-	outw(Cmd_INT|Cmd_Xmit,ioaddr);
-	outw(lp->tx_head+0x08,ioaddr);
-	outw(lp->tx_head+0x0e,ioaddr);
-	outw(0x0000,ioaddr);
-	outw(0x0000,ioaddr);
-	outw(lp->tx_head+0x08,ioaddr);
-	outw(0x8000|len,ioaddr);
-	outw(-1,ioaddr);
-	outw(lp->tx_head+0x16,ioaddr);
-	outw(0,ioaddr);
-	outsw(ioaddr,buf,(len+1)>>1);
-	outw(lp->tx_tail+0x0c,ioaddr+WRITE_PTR);
-	outw(lp->tx_head,ioaddr);
+	outw(lp->tx_head, ioaddr + WRITE_PTR);
+
+	outw(0x0000, ioaddr + DATAPORT);
+        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+	outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+	outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
+
+	outw(0x0000, ioaddr + DATAPORT);
+	outw(0x0000, ioaddr + DATAPORT);
+	outw(lp->tx_head+0x08, ioaddr + DATAPORT);
+
+	outw(0x8000|len, ioaddr + DATAPORT);
+	outw(-1, ioaddr + DATAPORT);
+	outw(lp->tx_head+0x16, ioaddr + DATAPORT);
+	outw(0, ioaddr + DATAPORT);
+
+        outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
+
+	outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
+	outw(lp->tx_head, ioaddr + DATAPORT);
+
 	dev->trans_start = jiffies;
 	lp->tx_tail = lp->tx_head;
 	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 
@@ -677,24 +738,31 @@
 		lp->tx_head += TX_BUF_SIZE;
 	if (lp->tx_head != lp->tx_reap) 
 		dev->tbusy = 0;
-	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
 /*
  * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and
- * initialize buffer memory pointers. These should
- * probably be held in dev->priv, in case someone has 2
- * differently configured cards in their box (Arghhh!)
+ * Read hardware address, reset card, size memory and initialize buffer
+ * memory pointers. These are held in dev->priv, in case someone has more
+ * than one card in a machine.
  */
 
 static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 {
 	unsigned short hw_addr[3];
+	unsigned int memory_size;
+	static char *ifmap[]={"AUI", "BNC", "RJ45"};
+	enum iftype {AUI=0, BNC=1, TP=2};
 	int i;
-	unsigned char *chw_addr = (unsigned char *)hw_addr;
+	unsigned short xsum = 0;
+	struct net_local *lp;
+
+	printk("%s: EtherExpress 16 at %#x",dev->name,ioaddr);
 
-	printk("%s: EtherExpress at %#x, ",dev->name,ioaddr);
+	outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
+	outb(0, ioaddr+EEPROM_Ctrl);
+	udelay(500);
+	outb(i586_RST, ioaddr+EEPROM_Ctrl);
 
 	hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
 	hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
@@ -702,90 +770,86 @@
 
 	if (hw_addr[2]!=0x00aa || ((hw_addr[1] & 0xff00)!=0x0000)) 
 	{
-		printk("rejected: invalid address %04x%04x%04x\n",
+		printk(" rejected: invalid address %04x%04x%04x\n",
 			hw_addr[2],hw_addr[1],hw_addr[0]);
 		return ENODEV;
 	}
 
+	/* Calculate the EEPROM checksum.  Carry on anyway if it's bad,
+	 * though. 
+	 */
+	for (i = 0; i < 64; i++)
+		xsum += eexp_hw_readeeprom(ioaddr, i);
+	if (xsum != 0xbaba) 
+		printk(" (bad EEPROM xsum 0x%02x)", xsum);
+
 	dev->base_addr = ioaddr;
 	for ( i=0 ; i<6 ; i++ ) 
-		dev->dev_addr[i] = chw_addr[5-i];
+		dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
 
 	{
 		char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};
-		char *ifmap[]={"AUI", "BNC", "10baseT"};
-		enum iftype {AUI=0, BNC=1, TP=2};
 		unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
 
-		dev->irq = irqmap[setupval>>13];
+		/* Use the IRQ from EEPROM if none was given */
+		if (!dev->irq)
+			dev->irq = irqmap[setupval>>13];
+
 		dev->if_port = !(setupval & 0x1000) ? AUI :
 			eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TP : BNC;
-
-		printk("IRQ %d, Interface %s, ",dev->irq,ifmap[dev->if_port]);
-
-		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-		outb(0,ioaddr+SET_IRQ);
 	}
 
-	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL);
 	if (!dev->priv) 
-		return -ENOMEM;
+		return ENOMEM;
 
 	memset(dev->priv, 0, sizeof(struct net_local));
+	
+	printk("; using IRQ %d, %s connector", dev->irq,ifmap[dev->if_port]);
 
-	eexp_hw_ASICrst(dev);
+	/* Find out how much RAM we have on the card */
+	outw(0, dev->base_addr + WRITE_PTR);
+	for (i = 0; i < 32768; i++)
+		outw(0, dev->base_addr + DATAPORT);
+
+        for (memory_size = 0; memory_size < 64; memory_size++)
+	{
+		outw(memory_size<<10, dev->base_addr + WRITE_PTR);
+		outw(memory_size<<10, dev->base_addr + READ_PTR);
+		if (inw(dev->base_addr+DATAPORT)) 
+			break;
+		outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
+		outw(memory_size<<10, dev->base_addr + READ_PTR);
+		if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
+			break;
+	}
 
-	{
-		unsigned short i586mso = 0x023e;
-		unsigned short old_wp,old_rp,old_a0,old_a1;
-		unsigned short a0_0,a1_0,a0_1,a1_1;
-
-		old_wp = inw(ioaddr+WRITE_PTR);
-		old_rp = inw(ioaddr+READ_PTR);
-		outw(0x8000+i586mso,ioaddr+READ_PTR);
-		old_a1 = inw(ioaddr);
-		outw(i586mso,ioaddr+READ_PTR);
-		old_a0 = inw(ioaddr);
-		outw(i586mso,ioaddr+WRITE_PTR);
-		outw(0x55aa,ioaddr);
-		outw(i586mso,ioaddr+READ_PTR);
-		a0_0 = inw(ioaddr);
-		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
-		outw(0x5a5a,ioaddr);
-		outw(0x8000+i586mso,ioaddr+READ_PTR);
-		a1_0 = inw(ioaddr);
-		outw(i586mso,ioaddr+READ_PTR);
-		a0_1 = inw(ioaddr);
-		outw(i586mso,ioaddr+WRITE_PTR);
-		outw(0x1234,ioaddr);
-		outw(0x8000+i586mso,ioaddr+READ_PTR);
-		a1_1 = inw(ioaddr);
+	/* Sort out the number of buffers.  We may have 16, 32, 48 or 64k
+	 * of RAM to play with.
+	 */
+	lp->num_tx_bufs = 4;
+	lp->rx_buf_end = 0x3ff6;
+	switch (memory_size)
+	{
+	case 64:
+		lp->rx_buf_end += 0x4000;
+	case 48:
+		lp->num_tx_bufs += 4;
+		lp->rx_buf_end += 0x4000;
+	case 32:
+		lp->rx_buf_end += 0x4000;
+	case 16:
+		printk(", %dk RAM.\n", memory_size);
+		break;
+	default:
+		printk("; bad memory size (%dk).\n", memory_size);
+		kfree(dev->priv);
+		return ENODEV;
+		break;
+	}
 
-		if ((a0_0 != a0_1) || (a1_0 != a1_1) ||
-			(a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 
-		{
-			printk("32k\n");
-			PRIV(dev)->rx_buf_end = 0x7ff6;
-			PRIV(dev)->num_tx_bufs = 4;
-		}
-		else
-		{
-			printk("64k\n");
-			PRIV(dev)->num_tx_bufs = 8;
-			PRIV(dev)->rx_buf_start = TX_BUF_START + (PRIV(dev)->num_tx_bufs*TX_BUF_SIZE);
-			PRIV(dev)->rx_buf_end = 0xfff6;
-		}
+	lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
 
-		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
-		outw(old_a1,ioaddr);
-		outw(i586mso,ioaddr+WRITE_PTR);
-		outw(old_a0,ioaddr);
-		outw(old_wp,ioaddr+WRITE_PTR);
-		outw(old_rp,ioaddr+READ_PTR);
-	}
-  
-	if (net_debug) 
-		printk(version);
 	dev->open = eexp_open;
 	dev->stop = eexp_close;
 	dev->hard_start_xmit = eexp_xmit;
@@ -796,16 +860,18 @@
 }
 
 /*
- *	Read a word from eeprom location (0-63?)
+ * 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)
+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;
 	int i;
  
 	outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
-	for ( i=0x100 ; i ; i>>=1 ) 
+	for (i=0x100 ; i ; i>>=1 ) 
 	{
 		if (cmd&i) 
 			wval |= EC_Wr;
@@ -820,7 +886,7 @@
 	}	
 	wval &= ~EC_Wr;
 	outb(wval,ioaddr+EEPROM_Ctrl);
-	for ( i=0x8000 ; i ; i>>=1 ) 
+	for (i=0x8000 ; i ; i>>=1 ) 
 	{
 		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
 		eeprom_delay();
@@ -850,24 +916,19 @@
 static unsigned short eexp_hw_lasttxstat(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short old_rp = inw(ioaddr+READ_PTR);
-	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 	unsigned short tx_block = lp->tx_reap;
 	unsigned short status;
   
-	if (!test_bit(0,(void *)&dev->tbusy) && lp->tx_head==lp->tx_reap) 
+	if ((!dev->tbusy) && lp->tx_head==lp->tx_reap) 
 		return 0x0000;
 
 	do
 	{
-		outw(tx_block,ioaddr+READ_PTR);
-		status = inw(ioaddr);
+		outw(tx_block, dev->base_addr + SM_PTR);
+		status = inw(SHADOW(tx_block));
 		if (!Stat_Done(status)) 
 		{
 			lp->tx_link = tx_block;
-			outw(old_rp,ioaddr+READ_PTR);
-			outw(old_wp,ioaddr+WRITE_PTR);
 			return status;
 		}
 		else 
@@ -896,17 +957,14 @@
 	while (lp->tx_reap != lp->tx_head);
 
 	lp->tx_link = lp->tx_tail + 0x08;
-	outw(old_rp,ioaddr+READ_PTR);
-	outw(old_wp,ioaddr+WRITE_PTR);
 
 	return status;
 }
 
 /* 
- * This should never happen. It is called when some higher
- * routine detects the CU has stopped, to try to restart
- * it from the last packet we knew we were working on,
- * or the idle loop if we had finished for the time.
+ * This should never happen. It is called when some higher routine detects
+ * that the CU has stopped, to try to restart it from the last packet we knew
+ * we were working on, or the idle loop if we had finished for the time.
  */
 
 static void eexp_hw_txrestart(struct device *dev)
@@ -915,24 +973,21 @@
 	unsigned short ioaddr = dev->base_addr;
   
 	lp->last_tx_restart = lp->tx_link;
-	outw(lp->tx_link,ioaddr+SCB_CBL);
-	outw(SCB_CUstart,ioaddr+SCB_CMD);
-	outw(0,ioaddr+SCB_STATUS);
+	scb_wrcbl(dev, lp->tx_link);
+	scb_command(dev, SCB_CUstart);
 	outb(0,ioaddr+SIGNAL_CA);
 
 	{
 		unsigned short boguscount=50,failcount=5;
-		while (!inw(ioaddr+SCB_STATUS)) 
+		while (!scb_status(dev)) 
 		{
 			if (!--boguscount) 
 			{
 				if (--failcount) 
 				{
-					printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n",
-						dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
-					outw(lp->tx_link,ioaddr+SCB_CBL);
-					outw(0,ioaddr+SCB_STATUS);
-					outw(SCB_CUstart,ioaddr+SCB_CMD);
+					printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
+				        scb_wrcbl(dev, lp->tx_link);
+					scb_command(dev, SCB_CUstart);
 					outb(0,ioaddr+SIGNAL_CA);
 					boguscount = 100;
 				}
@@ -950,40 +1005,39 @@
 }
 
 /*
- * Writes down the list of transmit buffers into card
- * memory. Initial separate, repeated transmits link
- * them into a circular list, such that the CU can
- * be constantly active, and unlink them as we reap
- * transmitted packet buffers, so the CU doesn't loop
- * and endlessly transmit packets. (Try hacking the driver
- * to send continuous broadcast messages, say ARP requests
- * on a subnet with Windows boxes running on Novell and
- * LAN Workplace with EMM386. Amusing to watch them all die
- * horribly leaving the Linux boxes up!)
+ * Writes down the list of transmit buffers into card memory.  Each
+ * entry consists of an 82586 transmit command, followed by a jump
+ * pointing to itself.  When we want to transmit a packet, we write 
+ * the data into the appropriate transmit buffer and then modify the
+ * preceding jump to point at the new transmit command.  This means that
+ * the 586 command unit is continuously active. 
  */
 
 static void eexp_hw_txinit(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 	unsigned short tx_block = TX_BUF_START;
 	unsigned short curtbuf;
+	unsigned short ioaddr = dev->base_addr;
 
 	for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ ) 
 	{
-		outw(tx_block,ioaddr+WRITE_PTR);
-		outw(0x0000,ioaddr);
-		outw(Cmd_INT|Cmd_Xmit,ioaddr);
-		outw(tx_block+0x08,ioaddr);
-		outw(tx_block+0x0e,ioaddr);
-		outw(0x0000,ioaddr);
-		outw(0x0000,ioaddr);
-		outw(tx_block+0x08,ioaddr);
-		outw(0x8000,ioaddr);
-		outw(-1,ioaddr);
-		outw(tx_block+0x16,ioaddr);
-		outw(0x0000,ioaddr);
+		outw(tx_block, ioaddr + WRITE_PTR);
+
+	        outw(0x0000, ioaddr + DATAPORT);
+		outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
+		outw(tx_block+0x08, ioaddr + DATAPORT);
+		outw(tx_block+0x0e, ioaddr + DATAPORT);
+
+		outw(0x0000, ioaddr + DATAPORT);
+		outw(0x0000, ioaddr + DATAPORT);
+		outw(tx_block+0x08, ioaddr + DATAPORT);
+
+		outw(0x8000, ioaddr + DATAPORT);
+		outw(-1, ioaddr + DATAPORT);
+		outw(tx_block+0x16, ioaddr + DATAPORT);
+		outw(0x0000, ioaddr + DATAPORT);
+
 		tx_block += TX_BUF_SIZE;
 	}
 	lp->tx_head = TX_BUF_START;
@@ -991,116 +1045,123 @@
 	lp->tx_tail = tx_block - TX_BUF_SIZE;
 	lp->tx_link = lp->tx_tail + 0x08;
 	lp->rx_buf_start = tx_block;
-	outw(old_wp,ioaddr+WRITE_PTR);
-}
-
-/* is this a standard test pattern, or dbecker randomness? */
 
-unsigned short rx_words[] = 
-{
-	0xfeed,0xf00d,0xf001,0x0505,0x2424,0x6565,0xdeaf
-};
+}
 
 /*
- * Write the circular list of receive buffer descriptors to
- * card memory. Note, we no longer mark the end of the list,
- * so if all the buffers fill up, the 82586 will loop until
- * we free one. This may sound dodgy, but it works, and
- * it makes the error detection in the interrupt handler
- * a lot simpler.
+ * Write the circular list of receive buffer descriptors to card memory.
+ * The end of the list isn't marked, which means that the 82586 receive
+ * unit will loop until buffers become available (this avoids it giving us
+ * "out of resources" messages). 
  */
 
 static void eexp_hw_rxinit(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 	unsigned short rx_block = lp->rx_buf_start;
+	unsigned short ioaddr = dev->base_addr; 
 
 	lp->num_rx_bufs = 0;
 	lp->rx_first = rx_block;
 	do 
 	{
 		lp->num_rx_bufs++;
-		outw(rx_block,ioaddr+WRITE_PTR);
-		outw(0x0000,ioaddr);
-		outw(0x0000,ioaddr);
-		outw(rx_block+RX_BUF_SIZE,ioaddr);
-		outw(rx_block+0x16,ioaddr);
-		outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
-		outw(0x8000,ioaddr);
-		outw(-1,ioaddr);
-		outw(rx_block+0x20,ioaddr);
-		outw(0x0000,ioaddr);
-		outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
+
+		outw(rx_block, ioaddr + WRITE_PTR);
+		
+		outw(0, ioaddr + DATAPORT);  outw(0, ioaddr+DATAPORT);
+		outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
+		outw(rx_block + 0x16, ioaddr+DATAPORT);
+
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		outw(0xdead, ioaddr+DATAPORT);
+		
+		outw(0x8000, ioaddr+DATAPORT); 
+		outw(0xffff, ioaddr+DATAPORT);
+		outw(rx_block + 0x20, ioaddr+DATAPORT);
+		outw(0, ioaddr+DATAPORT);
+		outw(0x8000 | (RX_BUF_SIZE-0x20), ioaddr+DATAPORT);
+
 		lp->rx_last = rx_block;
 		rx_block += RX_BUF_SIZE;
 	} while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
 
-	outw(lp->rx_last+4,ioaddr+WRITE_PTR);
-	outw(lp->rx_first,ioaddr);
+	outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
+	outw(lp->rx_first, ioaddr+DATAPORT);
 
-	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
 /*
- * Reset the 586, fill memory (including calls to
- * eexp_hw_[(rx)(tx)]init()) unreset, and start
- * the configuration sequence. We don't wait for this
- * to finish, but allow the interrupt handler to start
- * the CU and RU for us. We can't start the receive/
- * transmission system up before we know that the
- * hardware is configured correctly
+ * Un-reset the 586, and start the configuration sequence. We don't wait for
+ * this to finish, but allow the interrupt handler to start the CU and RU for
+ * us.  We can't start the receive/transmission system up before we know that
+ * the hardware is configured correctly.
  */
 static void eexp_hw_init586(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
+	int i;
 
 #if NET_DEBUG > 6
-        printk("%s: eexp_hw_init586()\n", dev->name);
+	printk("%s: eexp_hw_init586()\n", dev->name);
 #endif
 
 	lp->started = 0;
-	set_loopback;
 
-	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-	outb_p(i586_RST,ioaddr+EEPROM_Ctrl);
-	udelay(2000);  /* delay 20ms */
-        {
-		unsigned long ofs;
-		for (ofs = 0; ofs < lp->rx_buf_end; ofs += 32) {
-			unsigned long i;
-			outw_p(ofs, ioaddr+SM_PTR);
-			for (i = 0; i < 16; i++) {
-				outw_p(0, ioaddr+SM_ADDR(i<<1));
-			}
-		}
-	}
+	set_loopback(dev);  
 
-	outw_p(lp->rx_buf_end,ioaddr+WRITE_PTR);
-	start_code[28] = (dev->flags & IFF_PROMISC)?(start_code[28] | 1):(start_code[28] & ~1);
+	/* Bash the startup code a bit */
+	start_code[28] = (dev->flags & IFF_PROMISC)?(start_code[28] | 1):
+		(start_code[28] & ~1);
 	lp->promisc = dev->flags & IFF_PROMISC;
-	/* We may die here */
-	outsw(ioaddr, start_code, sizeof(start_code)>>1);
-	outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
-	outsw(ioaddr,dev->dev_addr,3);
+	memcpy(&start_code[33], &dev->dev_addr[0], 6);
+
+	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); 
+
+	/* Download the startup code */
+	outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
+	outw(start_code[0], ioaddr + 0x8006);
+	outw(start_code[1], ioaddr + 0x8008);
+	outw(start_code[2], ioaddr + 0x800a);
+	outw(start_code[3], ioaddr + 0x800c);
+	outw(start_code[4], ioaddr + 0x800e);
+	for (i = 10; i < (sizeof(start_code)); i+=32) {
+		int j;
+		outw(i-10, ioaddr + SM_PTR);
+		for (j = 0; j < 16; j+=2)
+			outw(start_code[(i+j)/2],
+			     ioaddr+0x4000+j);
+		for (j = 0; j < 16; j+=2)
+			outw(start_code[(i+j+16)/2],
+			     ioaddr+0x8000+j);
+	}
+
 	eexp_hw_txinit(dev);
 	eexp_hw_rxinit(dev);
-	outw(0,ioaddr+WRITE_PTR);
-	outw(1,ioaddr);
+
 	outb(0,ioaddr+EEPROM_Ctrl);
-	outw(0,ioaddr+SCB_CMD);
+	udelay(5000);
+
+	scb_command(dev, 0xf000);
 	outb(0,ioaddr+SIGNAL_CA);
+
+	outw(0, ioaddr+SM_PTR);
+
 	{
 		unsigned short rboguscount=50,rfailcount=5;
-		while (outw(0,ioaddr+READ_PTR),inw(ioaddr)) 
+		while (inw(ioaddr+0x4000)) 
 		{
 			if (!--rboguscount) 
 			{
 				printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
 					dev->name);
-				outw(0,ioaddr+SCB_CMD);
+				scb_command(dev, 0);
 				outb(0,ioaddr+SIGNAL_CA);
 				rboguscount = 100;
 				if (!--rfailcount) 
@@ -1113,23 +1174,22 @@
 		}
 	}
 
-	outw(CONF_LINK,ioaddr+SCB_CBL);
-	outw(0,ioaddr+SCB_STATUS);
-	outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+        scb_wrcbl(dev, CONF_LINK);
+	scb_command(dev, 0xf000|SCB_CUstart);
 	outb(0,ioaddr+SIGNAL_CA);
+
 	{
 		unsigned short iboguscount=50,ifailcount=5;
-		while (!inw(ioaddr+SCB_STATUS)) 
+		while (!scb_status(dev)) 
 		{
 			if (!--iboguscount) 
 			{
 				if (--ifailcount) 
 				{
 					printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
-						dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
-					outw(CONF_LINK,ioaddr+SCB_CBL);
-					outw(0,ioaddr+SCB_STATUS);
-					outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+						dev->name, scb_status(dev), scb_rdcmd(dev));
+					scb_wrcbl(dev, CONF_LINK);
+				        scb_command(dev, 0xf000|SCB_CUstart);
 					outb(0,ioaddr+SIGNAL_CA);
 					iboguscount = 100;
 				}
@@ -1142,8 +1202,9 @@
 		}
 	}
   
-	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-	clear_loopback;
+	clear_loopback(dev); 
+	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); 
+
 	lp->init_time = jiffies;
 #if NET_DEBUG > 6
         printk("%s: leaving eexp_hw_init586()\n", dev->name);
@@ -1151,57 +1212,13 @@
 	return;
 }
 
-/* 
- * completely reset the EtherExpress hardware. We will most likely get
- * an interrupt during this whether we want one or not. It is best,
- * therefore, to call this while we don't have a request_irq() on.
- */
-
-static void eexp_hw_ASICrst(struct device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short wrval = 0x0001,succount=0,boguscount=500;
-
-	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-	PRIV(dev)->started = 0;
-	outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
-	while (succount<20) 
-	{
-		if (wrval == 0xffff) 
-			wrval = 0x0001;
-		outw(0,ioaddr+WRITE_PTR);
-		outw(wrval,ioaddr);
-		outw(0,ioaddr+READ_PTR);
-		if (wrval++ == inw(ioaddr)) 
-			succount++;
-		else 
-		{
-			succount = 0;
-			if (!boguscount--) 
-			{
-				boguscount = 500;
-				printk("%s: Having problems resetting EtherExpress ASIC, continuing...\n",
-					dev->name);
-				wrval = 0x0001;
-				outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
-			}
-		}
-	}
-	outb(i586_RST,ioaddr+EEPROM_Ctrl);
-}
-
 
 /*
  * Set or clear the multicast filter for this adaptor.
- * We have to do a complete 586 restart for this to take effect.
- * At the moment only promiscuous mode is supported.
  */
 static void
 eexp_set_multicast(struct device *dev)
 {
-	if ((dev->flags & IFF_PROMISC) != PRIV(dev)->promisc)
-		eexp_hw_init586(dev);
 }
 
 
@@ -1221,8 +1238,8 @@
 	  0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe },  
 };
 
-int irq[EEXP_MAX_CARDS] = {0, };
-int io[EEXP_MAX_CARDS] = {0, };
+static int irq[EEXP_MAX_CARDS] = {0, };
+static int io[EEXP_MAX_CARDS] = {0, };
 
 /* Ideally the user would give us io=, irq= for every card.  If any parameters
  * are specified, we verify and then use them.  If no parameters are given, we
@@ -1271,6 +1288,5 @@
  * Local Variables:
  *  c-file-style: "linux"
  *  tab-width: 8
- *  compile-command: "gcc -D__KERNEL__ -I/discs/bibble/src/linux-1.3.69/include  -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE  -c 3c505.c"
  * End:
  */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/eexpress.h linux/drivers/net/eexpress.h
--- lx2.0/v2.0.21/linux/drivers/net/eexpress.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/eexpress.h	Sat Sep 28 22:06:12 1996
@@ -0,0 +1,179 @@
+/*
+ * eexpress.h: Intel EtherExpress16 defines
+ */
+
+/*
+ * EtherExpress card register addresses
+ * as offsets from the base IO region (dev->base_addr)
+ */
+
+#define DATAPORT      0x0000
+#define WRITE_PTR     0x0002
+#define READ_PTR      0x0004
+#define SIGNAL_CA     0x0006
+#define SET_IRQ       0x0007
+#define SM_PTR        0x0008
+#define	MEM_Dec	      0x000a
+#define MEM_Ctrl      0x000b
+#define MEM_Page_Ctrl 0x000c
+#define Config        0x000d
+#define EEPROM_Ctrl   0x000e
+#define ID_PORT       0x000f
+#define	MEM_ECtrl     0x000f
+
+/*
+ * card register defines
+ */
+
+/* SET_IRQ */
+#define SIRQ_en       0x08
+#define SIRQ_dis      0x00
+
+/* EEPROM_Ctrl */
+#define EC_Clk        0x01
+#define EC_CS         0x02
+#define EC_Wr         0x04
+#define EC_Rd         0x08
+#define ASIC_RST      0x40
+#define i586_RST      0x80
+
+#define eeprom_delay() { int _i = 40; while (--_i>0) { __SLOW_DOWN_IO; }}
+
+/*
+ * i82586 Memory Configuration
+ */
+
+/* (System Configuration Pointer) System start up block, read after 586_RST */
+#define SCP_START 0xfff6
+
+/* Intermediate System Configuration Pointer */
+#define ISCP_START 0x0000
+
+/* System Command Block */
+#define SCB_START 0x0008
+
+/* Start of buffer region.  Everything before this is used for control
+ * structures and the CU configuration program.  The memory layout is 
+ * determined in eexp_hw_probe(), once we know how much memory is 
+ * available on the card.
+ */
+
+#define TX_BUF_START 0x0100
+
+#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
+#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+
+/*
+ * SCB defines 
+ */
+
+/* these functions take the SCB status word and test the relevant status bit */
+#define SCB_complete(s) ((s&0x8000)!=0)
+#define SCB_rxdframe(s) ((s&0x4000)!=0)
+#define SCB_CUdead(s)   ((s&0x2000)!=0)
+#define SCB_RUdead(s)   ((s&0x1000)!=0)
+#define SCB_ack(s)      (s & 0xf000)
+
+/* Command unit status: 0=idle, 1=suspended, 2=active */
+#define SCB_CUstat(s)   ((s&0x0300)>>8)
+
+/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
+#define SCB_RUstat(s)   ((s&0x0070)>>4)
+
+/* SCB commands */
+#define SCB_CUnop       0x0000
+#define SCB_CUstart     0x0100
+#define SCB_CUresume    0x0200
+#define SCB_CUsuspend   0x0300
+#define SCB_CUabort     0x0400
+#define SCB_resetchip   0x0080
+
+#define SCB_RUnop       0x0000
+#define SCB_RUstart     0x0010
+#define SCB_RUresume    0x0020
+#define SCB_RUsuspend   0x0030
+#define SCB_RUabort     0x0040
+
+/*
+ * Command block defines 
+ */
+
+#define Stat_Done(s)    ((s&0x8000)!=0)
+#define Stat_Busy(s)    ((s&0x4000)!=0)
+#define Stat_OK(s)      ((s&0x2000)!=0)
+#define Stat_Abort(s)   ((s&0x1000)!=0)
+#define Stat_STFail     ((s&0x0800)!=0)
+#define Stat_TNoCar(s)  ((s&0x0400)!=0)
+#define Stat_TNoCTS(s)  ((s&0x0200)!=0)
+#define Stat_TNoDMA(s)  ((s&0x0100)!=0)
+#define Stat_TDefer(s)  ((s&0x0080)!=0)
+#define Stat_TColl(s)   ((s&0x0040)!=0)
+#define Stat_TXColl(s)  ((s&0x0020)!=0)
+#define Stat_NoColl(s)  (s&0x000f)
+
+/* Cmd_END will end AFTER the command if this is the first
+ * command block after an SCB_CUstart, but BEFORE the command
+ * for all subsequent commands. Best strategy is to place
+ * Cmd_INT on the last command in the sequence, followed by a
+ * dummy Cmd_Nop with Cmd_END after this.
+ */
+
+#define Cmd_END     0x8000
+#define Cmd_SUS     0x4000
+#define Cmd_INT     0x2000
+
+#define Cmd_Nop     0x0000
+#define Cmd_SetAddr 0x0001
+#define Cmd_Config  0x0002
+#define Cmd_MCast   0x0003
+#define Cmd_Xmit    0x0004
+#define Cmd_TDR     0x0005
+#define Cmd_Dump    0x0006
+#define Cmd_Diag    0x0007
+
+
+/*
+ * Frame Descriptor (Receive block) defines
+ */
+
+#define FD_Done(s)  ((s&0x8000)!=0)
+#define FD_Busy(s)  ((s&0x4000)!=0)
+#define FD_OK(s)    ((s&0x2000)!=0)
+
+#define FD_CRC(s)   ((s&0x0800)!=0)
+#define FD_Align(s) ((s&0x0400)!=0)
+#define FD_Resrc(s) ((s&0x0200)!=0)
+#define FD_DMA(s)   ((s&0x0100)!=0)
+#define FD_Short(s) ((s&0x0080)!=0)
+#define FD_NoEOF(s) ((s&0x0040)!=0)
+
+struct rfd_header {
+	volatile unsigned long flags;
+	volatile unsigned short link;
+	volatile unsigned short rbd_offset;
+	volatile unsigned short dstaddr1;
+	volatile unsigned short dstaddr2;
+	volatile unsigned short dstaddr3;
+	volatile unsigned short srcaddr1;
+	volatile unsigned short srcaddr2;
+	volatile unsigned short srcaddr3;
+	volatile unsigned short length;
+  
+	/* This is actually a Receive Buffer Descriptor.  The way we 
+	 * arrange memory means that an RBD always follows the RFD that 
+	 * points to it, so they might as well be in the same structure.
+	 */
+	volatile unsigned short actual_count;
+	volatile unsigned short next_rbd;
+	volatile unsigned short buf_addr1;
+	volatile unsigned short buf_addr2;
+	volatile unsigned short size;
+};
+
+/* Returned data from the Time Domain Reflectometer */
+
+#define TDR_LINKOK       (1<<15)
+#define TDR_XCVRPROBLEM  (1<<14)
+#define TDR_OPEN         (1<<13)
+#define TDR_SHORT        (1<<12)
+#define TDR_TIME         0x7ff
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- lx2.0/v2.0.21/linux/drivers/net/eql.c	Mon May  6 12:26:08 1996
+++ linux/drivers/net/eql.c	Sun Sep 22 21:17:21 1996
@@ -17,7 +17,7 @@
  */
 
 static const char *version = 
-	"Equalizer1996: $Revision: 1.2 $ $Date: 1996/04/11 17:51:52 $ Simon Janes (simon@ncm.com)\n";
+	"Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n";
 
 /*
  * Sources:
@@ -459,28 +459,35 @@
 
 	if (master_dev != 0 && slave_dev != 0)
 	{
-		if (! eql_is_master (slave_dev)  &&   /* slave is not a master */
-			! eql_is_slave (slave_dev)      ) /* slave is not already a slave */
-		{
-			slave_t *s = eql_new_slave ();
-			equalizer_t *eql = (equalizer_t *) master_dev->priv;
-			s->dev = slave_dev;
-			s->priority = srq.priority;
-			s->priority_bps = srq.priority;
-			s->priority_Bps = srq.priority / 8;
-			slave_dev->flags |= IFF_SLAVE;
-			eql_insert_slave (eql->queue, s);
-			return 0;
+		if ((master_dev->flags & IFF_UP) == IFF_UP)
+                {
+			/*slave is not a master & not already a slave:*/
+			if (! eql_is_master (slave_dev)  &&
+			    ! eql_is_slave (slave_dev) )
+			{
+				slave_t *s = eql_new_slave ();
+				equalizer_t *eql = 
+					(equalizer_t *) master_dev->priv;
+				s->dev = slave_dev;
+				s->priority = srq.priority;
+				s->priority_bps = srq.priority;
+				s->priority_Bps = srq.priority / 8;
+				slave_dev->flags |= IFF_SLAVE;
+				eql_insert_slave (eql->queue, s);
+				return 0;
+			}
+#ifdef EQL_DEBUG
+			else if (eql_debug >= 20)
+				printk ("EQL enslave: slave is master or slave is already slave\n");
+#endif  
 		}
 #ifdef EQL_DEBUG
-	if (eql_debug >= 20)
-		printk ("EQL enslave: slave is master or slave is already slave\n");
+		else if (eql_debug >= 20)
+			printk ("EQL enslave: master device not up!\n");
 #endif  
-
-		return -EINVAL;
 	}
 #ifdef EQL_DEBUG
-	if (eql_debug >= 20)
+	else if (eql_debug >= 20)
 		printk ("EQL enslave: master or slave are NULL");
 #endif  
 	return -EINVAL;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/eth82586.h linux/drivers/net/eth82586.h
--- lx2.0/v2.0.21/linux/drivers/net/eth82586.h	Fri Apr 12 09:49:37 1996
+++ linux/drivers/net/eth82586.h	Thu Jan  1 02:00:00 1970
@@ -1,172 +0,0 @@
-/*
- * eth82586.h: Intel EtherExpress defines
- *
- * Written 1995 by John Sullivan
- * See eexpress.c for further details
- * documentation and usage to do.
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT 0x0000
-#define WRITE_PTR 0x0002
-#define READ_PTR 0x0004
-#define SIGNAL_CA 0x0006
-#define SET_IRQ 0x0007
-#define SM_PTR 0x0008
-#define MEM_Ctrl 0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config 0x000d
-#define EEPROM_Ctrl 0x000e
-#define ID_PORT 0x000f
-
-/*
- * offset to shadowed memory, 0 <= x <= 31. We don't use this yet,
- * but may in the future. Is shadow memory access any faster than
- * dataport access?
- */
-#define SM_ADDR(x) (0x4000+((x&0x10)<<10)+(x&0xf))
-
-/* Always mirrors eexp-memory at 0x0008-0x000f */
-#define SCB_STATUS 0xc008
-#define SCB_CMD 0xc00a
-#define SCB_CBL 0xc00c
-#define SCB_RFA 0xc00e
-
-
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en 0x08
-#define SIRQ_dis 0x00
-
-/* Config */
-#define set_loopback outb(inb(ioaddr+Config)|0x02,ioaddr+Config)
-#define clear_loopback outb(inb(ioaddr+Config)&0xfd,ioaddr+Config)
-
-/* EEPROM_Ctrl */
-#define EC_Clk 0x01
-#define EC_CS  0x02
-#define EC_Wr  0x04
-#define EC_Rd  0x08
-#define ASIC_RST 0x40
-#define i586_RST  0x80
-
-#define eeprom_delay() { int _i = 40; while (--_i>0) { __SLOW_DOWN_IO; }}
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-/* System Command Block */
-#define SCB_START 0x0008
-
-/*
- * Start of buffer region. If we have 64k memory, eexp_hw_probe() may raise
- * NUM_TX_BUFS. RX_BUF_END is set to the end of memory, and all space between
- * the transmit buffer region and end of memory used for as many receive buffers
- * as we can fit. See eexp_hw_[(rx)(tx)]init().
- */
-#define TX_BUF_START 0x0100
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) ((s&0x8000)!=0)
-#define SCB_rxdframe(s) ((s&0x4000)!=0)
-#define SCB_CUdead(s) ((s&0x2000)!=0)
-#define SCB_RUdead(s) ((s&0x1000)!=0)
-#define SCB_ack(s) (s & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s) ((s&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s) ((s&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop     0x0000
-#define SCB_CUstart   0x0100
-#define SCB_CUresume  0x0200
-#define SCB_CUsuspend 0x0300
-#define SCB_CUabort   0x0400
-
-/* ? */
-#define SCB_resetchip 0x0080
-
-#define SCB_RUnop     0x0000
-#define SCB_RUstart   0x0010
-#define SCB_RUresume  0x0020
-#define SCB_RUsuspend 0x0030
-#define SCB_RUabort   0x0040
-
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s)   ((s&0x8000)!=0)
-#define Stat_Busy(s)   ((s&0x4000)!=0)
-#define Stat_OK(s)     ((s&0x2000)!=0)
-#define Stat_Abort(s)  ((s&0x1000)!=0)
-#define Stat_STFail    ((s&0x0800)!=0)
-#define Stat_TNoCar(s) ((s&0x0400)!=0)
-#define Stat_TNoCTS(s) ((s&0x0200)!=0)
-#define Stat_TNoDMA(s) ((s&0x0100)!=0)
-#define Stat_TDefer(s) ((s&0x0080)!=0)
-#define Stat_TColl(s)  ((s&0x0040)!=0)
-#define Stat_TXColl(s) ((s&0x0020)!=0)
-#define Stat_NoColl(s) (s&0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-#define Cmd_END     0x8000
-#define Cmd_SUS     0x4000
-#define Cmd_INT     0x2000
-
-#define Cmd_Nop     0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config  0x0002
-#define Cmd_MCast   0x0003
-#define Cmd_Xmit    0x0004
-#define Cmd_TDR     0x0005
-#define Cmd_Dump    0x0006
-#define Cmd_Diag    0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s)  ((s&0x8000)!=0)
-#define FD_Busy(s)  ((s&0x4000)!=0)
-#define FD_OK(s)    ((s&0x2000)!=0)
-
-#define FD_CRC(s)   ((s&0x0800)!=0)
-#define FD_Align(s) ((s&0x0400)!=0)
-#define FD_Resrc(s) ((s&0x0200)!=0)
-#define FD_DMA(s)   ((s&0x0100)!=0)
-#define FD_Short(s) ((s&0x0080)!=0)
-#define FD_NoEOF(s) ((s&0x0040)!=0)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- lx2.0/v2.0.21/linux/drivers/net/hp100.c	Fri Apr 12 09:49:38 1996
+++ linux/drivers/net/hp100.c	Wed Sep 25 11:51:08 1996
@@ -390,9 +390,9 @@
         }
       if ( mem_mapped && bus == HP100_BUS_PCI )
         {
-          if ( ( mem_ptr_virt = vremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
+          if ( ( mem_ptr_virt = ioremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
             {
-              printk( "hp100: vremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
+              printk( "hp100: ioremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
               mem_ptr_phys = NULL;
               mem_mapped = 0;
             }
@@ -1132,7 +1132,7 @@
   unregister_netdev( &dev_hp100 );
   release_region( dev_hp100.base_addr, HP100_REGION_SIZE );
   if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt )
-    vfree( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
+    iounmap( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
   kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
   dev_hp100.priv = NULL;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- lx2.0/v2.0.21/linux/drivers/scsi/53c7,8xx.c	Tue Jul 16 12:02:42 1996
+++ linux/drivers/scsi/53c7,8xx.c	Fri Sep 27 00:15:41 1996
@@ -452,7 +452,7 @@
  *     the right way, we need to provide options to reverse words
  *     when the scripts are relocated.
  *
- * 7.  Use vremap() to access memory mapped boards.  
+ * 7.  Use ioremap() to access memory mapped boards.  
  */
 
 /* 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- lx2.0/v2.0.21/linux/drivers/scsi/AM53C974.c	Fri Apr 12 09:49:40 1996
+++ linux/drivers/scsi/AM53C974.c	Sat Sep 28 11:22:47 1996
@@ -156,6 +156,11 @@
 static int commandline_current = 0;
 override_t overrides[7] = { {-1, 0, 0, 0}, };   /* LILO overrides */
 
+struct proc_dir_entry proc_scsi_am53c974 = {
+	PROC_SCSI_AM53C974, 8, "am53c974",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
 #ifdef AM53C974_DEBUG
 static int deb_stop = 1;
 
@@ -564,6 +569,8 @@
 {
 int count;        /* number of boards detected */
 
+tpnt->proc_dir = &proc_scsi_am53c974;
+
 #if defined (CONFIG_PCI)
 if (pcibios_present())
    count = AM53C974_bios_detect(tpnt);
@@ -596,7 +603,7 @@
 
 #ifdef AM53C974_OPTION_DEBUG_PROBE_ONLY
    printk ("AM53C974: probe only enabled, aborting initialization\n");
-   return -1;
+   return 0;
 #endif
 
 instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
@@ -659,7 +666,7 @@
    if (request_irq(instance->irq, AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
       printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq);
       scsi_unregister(instance);
-      return -1; } 
+      return 0; } 
    }
   else {
    printk("scsi%d: using interrupt handler previously installed for scsi%d\n",
@@ -677,8 +684,7 @@
 AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
 udelay(10);
 AM53C974_config_after_reset(instance);
-
-return(0);
+return(1);
 }
 
 /*********************************************************************
@@ -1797,7 +1803,11 @@
    AM53C974_write_8(CMDREG, CMDREG_CFIFO); /* clear FIFO */
    }                  
 
+#ifdef AM53C974_PROHIBIT_DISCONNECT
+tmp[0] = IDENTIFY(0, cmd->lun);
+#else
 tmp[0] = IDENTIFY(1, cmd->lun);
+#endif
 
 #ifdef SCSI2
 if (cmd->device->tagged_queue && (tag != TAG_NONE)) {
@@ -2005,7 +2015,7 @@
 AM53C974_write_8(STCMREG, (unsigned char)((length & 0xff00) >> 8));
 AM53C974_write_8(STCHREG, (unsigned char)((length & 0xff0000) >> 16));
 AM53C974_write_32(DMASTC, length & 0xffffff);
-AM53C974_write_32(DMASPA, (unsigned long)data);
+AM53C974_write_32(DMASPA, virt_to_bus(data));
 AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA);
 AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START);
 }
@@ -2241,3 +2251,9 @@
 cmd->scsi_done(cmd);
 return SCSI_ABORT_SUCCESS;
 }
+
+#ifdef MODULE
+static Scsi_Host_Template driver_template = AM53C974;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/AM53C974.h linux/drivers/scsi/AM53C974.h
--- lx2.0/v2.0.21/linux/drivers/scsi/AM53C974.h	Thu May  2 07:48:53 1996
+++ linux/drivers/scsi/AM53C974.h	Fri Sep 27 00:20:18 1996
@@ -47,6 +47,12 @@
 #define DEFAULT_RATE			 5 /* MHz, min: 3; max: 10 */
 #define DEFAULT_SYNC_OFFSET		 0 /* bytes, min: 0; max: 15; use 0 for async. mode */
 
+/***************************************************************************************
+* If defined, don't allow targets to disconnect during commands.  This will reduce     *
+* performance, but may be worthwhile if you suspect the driver of corrupting data when *
+* a disconnect happens.                                                                *
+***************************************************************************************/
+#define AM53C974_PROHIBIT_DISCONNECT
 
 /* --------------------- don't edit below here  --------------------- */
 
@@ -258,10 +264,12 @@
     unsigned  char max_offset[8];       /* max. sync. offset (setup), only valid if corresponding sync_en is nonzero */
     };
 
+extern struct proc_dir_entry proc_scsi_am53c974;
+
 #define AM53C974 { \
     NULL,              		/* pointer to next in list                      */  \
     NULL,			/* long * usage_count				*/  \
-    NULL,                       /* struct proc_dir_entry *proc_dir              */ \
+    &proc_scsi_am53c974,        /* struct proc_dir_entry *proc_dir              */ \
     NULL,                       /* int (*proc_info)(char *, char **, off_t, int, int, int); */ \
     "AM53C974",        		/* name                                         */  \
     AM53C974_detect,   		/* int (* detect)(struct SHT *)                 */  \
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- lx2.0/v2.0.21/linux/drivers/scsi/Makefile	Sat Jul  6 12:06:37 1996
+++ linux/drivers/scsi/Makefile	Fri Sep 20 18:42:32 1996
@@ -6,11 +6,6 @@
 # unless it's something special (ie not a .c file).
 #
 
-ifdef CONFIG_KERNEL_ELF
-# This is used for ELF - it needs to migrate or be moved.
-LD_RFLAG = -m elf_i386
-endif
-
 L_TARGET := scsi.a
 L_OBJS   := 
 M_OBJS   := 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/README.in2000 linux/drivers/scsi/README.in2000
--- lx2.0/v2.0.21/linux/drivers/scsi/README.in2000	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.in2000	Wed Sep 25 08:35:23 1996
@@ -0,0 +1,165 @@
+
+UPDATE NEWS: version 1.29 - 24 Sep 96
+
+   The memory-mapped hardware on the card is now accessed via
+   the 'readb()' and 'readl()' macros - required by the new
+   memory management scheme in the 2.1.x kernel series.
+   As suggested by Andries Brouwer, 'bios_param()' no longer
+   forces an artificial 1023 track limit on drives. Also
+   removed some kludge-code left over from struggles with
+   older (buggy) compilers.
+
+UPDATE NEWS: version 1.28 - 07 May 96
+
+   Tightened up the "interrupts enabled/disabled" discipline
+   in 'in2000_queuecommand()' and maybe 1 or 2 other places.
+   I _think_ it may have been a little too lax, causing an
+   occasional crash during full moon. A fully functional
+   /proc interface is now in place - if you want to play
+   with it, start by doing 'cat /proc/scsi/in2000/0'. You
+   can also use it to change a few run-time parameters on
+   the fly, but it's mostly for debugging. The curious
+   should take a good look at 'in2000_proc_info()' in the
+   in2000.c file to get an understanding of what it's all
+   about; I figure that people who are really into it will
+   want to add features suited to their own needs...
+   Also, sync is now DISABLED by default.
+
+UPDATE NEWS: version 1.27 - 10 Apr 96
+
+   Fixed a well-hidden bug in the adaptive-disconnect code
+   that would show up every now and then during extreme
+   heavy loads involving 2 or more simultaneously active
+   devices. Thanks to Joe Mack for keeping my nose to the
+   grindstone on this one.
+
+UPDATE NEWS: version 1.26 - 07 Mar 96
+
+   1.25 had a nasty bug that bit people with swap partitions
+   and tape drives. Also, in my attempt to guess my way
+   through Intel assembly language, I made an error in the
+   inline code for IO writes. Made a few other changes and
+   repairs - this version (fingers crossed) should work well.
+
+UPDATE NEWS: version 1.25 - 05 Mar 96
+
+   Kernel 1.3.70 interrupt mods added; old kernels still OK.
+   Big help from Bill Earnest and David Willmore on speed
+   testing and optimizing: I think there's a real improvement
+   in this area.
+   New! User-friendly command-line interface for LILO and
+   module loading - the old method is gone, so you'll need
+   to read the comments for 'setup_strings' near the top
+   of in2000.c. For people with CDROM's or other devices
+   that have a tough time with sync negotiation, you can
+   now selectively disable sync on individual devices -
+   search for the 'nosync' keyword in the command-line
+   comments. Some of you disable the BIOS on the card, which
+   caused the auto-detect function to fail; there is now a
+   command-line option to force detection of a ROM-less card.
+
+UPDATE NEWS: version 1.24a - 24 Feb 96
+
+   There was a bug in the synchronous transfer code. Only
+   a few people downloaded before I caught it - could have
+   been worse.
+
+UPDATE NEWS: version 1.24 - 23 Feb 96
+
+   Lots of good changes. Advice from Bill Earnest resulted
+   in much better detection of cards, more efficient usage
+   of the fifo, and (hopefully) faster data transfers. The
+   jury is still out on speed - I hope it's improved some.
+   One nifty new feature is a cool way of doing disconnect/
+   reselect. The driver defaults to what I'm calling
+   'adaptive disconnect' - meaning that each command is
+   evaluated individually as to whether or not it should be
+   run with the option to disconnect/reselect (if the device
+   chooses), or as a "SCSI-bus-hog". When several devices
+   are operating simultaneously, disconnects are usually an
+   advantage. In a single device system, or if only 1 device
+   is being accessed, transfers usually go faster if disconnects
+   are not allowed.
+
+
+
+The default arguments (you get these when you don't give an 'in2000'
+command-line argument, or you give a blank argument) will cause
+the driver to do adaptive disconnect, synchronous transfers, and a
+minimum of debug messages. If you want to fool with the options,
+search for 'setup_strings' near the top of the in2000.c file and
+check the 'hostdata->args' section in in2000.h - but be warned! Not
+everything is working yet (some things will never work, probably).
+I believe that disabling disconnects (DIS_NEVER) will allow you
+to choose a LEVEL2 value higher than 'L2_BASIC', but I haven't
+spent a lot of time testing this. You might try 'ENABLE_CLUSTERING'
+to see what happens: my tests showed little difference either way.
+There's also a define called 'DEFAULT_SX_PER'; this sets the data
+transfer speed for the asynchronous mode. I've put it at 500 ns
+despite the fact that the card could handle settings of 376 or
+252, because I'm not really sure if certain devices or maybe bad
+cables might have trouble at higher speeds. I couldn't find any
+info in my various SCSI references that talk about this in language
+I could understand, so decided to compromise with 500. This is still
+faster than the old driver was set at (I think). Can someone explain
+the significance of the bus transfer speed setting? Do devices on
+the bus ever care what it is? Is cable quality a factor here?
+Regardless, you can choose your own default through the command-
+line with the 'period' keyword.
+
+
+------------------------------------------------
+***********  DIP switch settings  **************
+------------------------------------------------
+
+   sw1-1 sw1-2    BIOS address (hex)
+   -----------------------------------------
+    off   off     C8000 - CBFF0
+    on    off     D8000 - DBFF0
+    off   on      D0000 - D3FF0
+    on    on      BIOS disabled
+
+   sw1-3 sw1-4    IO port address (hex)
+   ------------------------------------
+    off   off     220 - 22F
+    on    off     200 - 20F
+    off   on      110 - 11F
+    on    on      100 - 10F
+
+   sw1-5 sw1-6 sw1-7    Interrupt
+   ------------------------------
+    off   off   off     15
+    off   on    off     14
+    off   off   on      11
+    off   on    on      10
+    on    -     -       disabled
+
+   sw1-8 function depends on BIOS version. In earlier versions this
+   controlled synchronous data transfer support for MSDOS:
+      off = disabled
+      on  = enabled
+   In later ROMs (starting with 01.3 in April 1994) sw1-8 controls
+   the "greater than 2 disk drive" feature that first appeared in
+   MSDOS 5.0 (ignored by Linux):
+      off = 2 drives maximum
+      on  = 7 drives maximum
+
+   sw1-9    Floppy controller
+   --------------------------
+    off     disabled
+    on      enabled
+
+------------------------------------------------
+
+   I should mention that Drew Eckhardt's 'Generic NCR5380' sources
+   were my main inspiration, with lots of reference to the IN2000
+   driver currently distributed in the kernel source. I also owe
+   much to a driver written by Hamish Macdonald for Linux-m68k(!).
+   And to Eric Wright for being an ALPHA guinea pig. And to Bill
+   Earnest for 2 tons of great input and information. And to David
+   Willmore for extensive 'bonnie' testing. And to Joe Mack for
+   continual testing and feedback.
+
+
+            John Shifflett    jshiffle@netcom.com
+
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- lx2.0/v2.0.21/linux/drivers/scsi/advansys.c	Sat Aug 17 21:19:27 1996
+++ linux/drivers/scsi/advansys.c	Fri Sep 27 07:52:57 1996
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.15 1996/08/12 17:20:23 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -18,9 +18,9 @@
  */
 
 /*
- * The driver has been run with the v1.2.13, v1.3.57, and v2.0.11 kernels.
+ * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels.
  */
-#define ASC_VERSION "1.5"    /* AdvanSys Driver Version */
+#define ASC_VERSION "1.7"    /* AdvanSys Driver Version */
 
 /*
 
@@ -28,14 +28,15 @@
 
   A. Adapters Supported by this Driver
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
-  D. Source Comments
-  E. Driver Compile Time Options and Debugging
-  F. Driver LILO Option
-  G. Release History
-  H. Known Problems or Issues
-  I. Credits
-  J. AdvanSys Contact Information
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+  E. Source Comments
+  F. Driver Compile Time Options and Debugging
+  G. Driver LILO Option
+  H. Release History
+  I. Known Problems or Issues
+  J. Credits
+  K. AdvanSys Contact Information
 
   A. Adapters Supported by this Driver
  
@@ -47,8 +48,8 @@
      Descriptor Block) requests that can be stored in the RISC chip
      cache and board LRAM. A CDB is a single SCSI command. The driver
      detect routine will display the number of CDBs available for each
-     adapter detected. This value can be lowered in the BIOS by changing
-     the 'Host Queue Size' adapter setting.
+     adapter detected. The number of CDBs used by the driver can be
+     lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
@@ -56,8 +57,10 @@
         ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
         ABP920 - Bus-Master PCI (16 CDB)
         ABP930 - Bus-Master PCI (16 CDB)
+        ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
-  
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+     
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
         ABP742 - Bus-Master EISA (240 CDB)
@@ -65,6 +68,7 @@
         ABP940 - Bus-Master PCI (240 CDB)
         ABP940U - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+        ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
      
      Dual Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
@@ -72,17 +76,18 @@
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
      
      Footnotes:
-       1. These boards have been shipped by HP with the 4020i CD-R drive.
-          They have no BIOS so they cannot control a boot device, but they
-          can control secondary devices.
+       1. This board has been shipped by HP with the 4020i CD-R drive.
+          The board has no BIOS so it cannot control a boot device, but
+          it can control any secondary SCSI device.
    
-       2. This board has been shipped by Iomega with the Jaz Jet drive.
+       2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
   
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
      but precede v1.3.57 some of the changes for Linux v1.3.X listed
-     below may need to be modified or included.
+     below may need to be modified or included. A patch is available
+     for v1.2.13 from the AdvanSys WWW and FTP sites.
  
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
@@ -148,11 +153,13 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
  
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.3.57. For versions that precede v1.3.57
-     some of these changes may need to be modified or eliminated. Beginning
-     with v1.3.58 this driver is included with the Linux distribution.
+     some of these changes may need to be modified or eliminated. A patch
+     is available for v1.3.57 from the AdvanSys WWW and FTP sites.
+     Beginning with v1.3.58 this driver is included with the Linux
+     distribution eliminating the need for making any changes.
 
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
@@ -212,7 +219,21 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
 
-  D. Source Comments
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+
+     To upgrade the AdvanSys driver in a Linux v1.3.58 and newer
+     kernel, first check the version of the current driver. The
+     version is defined by the manifest constant ASC_VERSION at
+     the beginning of advansys.c. The new driver should have a
+     ASC_VERSION value greater than the current version. To install
+     the new driver rename advansys.c and advansys.h in the Linux
+     kernel source tree drivers/scsi directory to different names
+     or save them to a different directory in case you want to revert
+     to the old version of the driver. After the old driver is saved
+     copy the new advansys.c and advansys.h to drivers/scsi, rebuild
+     the kernel, and install the new kernel. No other changes are needed.
+
+  E. Source Comments
  
      1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
  
@@ -251,7 +272,7 @@
            --- Asc Library Constants and Macros
            --- Asc Library Functions
  
-  E. Driver Compile Time Options and Debugging
+  F. Driver Compile Time Options and Debugging
  
      In this source file the following constants can be defined. They are
      defined in the source below. Both of these options are enabled by
@@ -299,7 +320,7 @@
      2. ADVANSYS_STATS - enable statistics
  
         Statistics are maintained on a per adapter basis. Driver entry
-        point call counts and tranfer size counts are maintained.
+        point call counts and transfer size counts are maintained.
         Statistics are only available for kernels greater than or equal
         to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
 
@@ -315,7 +336,7 @@
         contain adapter and device configuration information.
 
 
-  F. Driver LILO Option
+  G. Driver LILO Option
  
      If init/main.c is modified as described in the 'Directions for Adding
      the AdvanSys Driver to Linux' section (B.4.) above, the driver will
@@ -346,7 +367,7 @@
      the 'Driver Compile Time Options and Debugging' section above for
      more information.
 
-  G. Release History
+  H. Release History
 
      BETA-1.0 (12/23/95): 
          First Release
@@ -389,7 +410,7 @@
             request_irq and supplying a dev_id pointer to both request_irq()
             and free_irq().
          3. In AscSearchIOPortAddr11() restore a call to check_region() which
-            should be used before any I/O port probing.
+            should be used before I/O port probing.
          4. Fix bug in asc_prt_hex() which resulted in the displaying
             the wrong data.
          5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
@@ -403,15 +424,28 @@
             made in v1.3.89. The advansys_select_queue_depths() function
             was added for the v1.3.89 changes.
 
-  H. Known Problems or Issues
+     1.6 (9/10/96):
+         1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
+
+     1.7 (9/25/96):
+         1. Enable clustering and optimize the setting of the maximum number
+            of scatter gather elements for any particular board. Clustering
+            increases CPU utilization, but results in a relatively larger
+            increase in I/O throughput.
+         2. Improve the performance of the request queuing functions by
+            adding a last pointer to the queue structure.
+         3. Correct problems with reset and abort request handling that
+            could have hung or crashed Linux.
+         4. Add more information to the adapter /proc file:
+            /proc/scsi/advansys[0...].
+         5. Remove the request timeout issue form the driver issues list.
+         6. Miscellaneous documentation additions and changes.
+
+  I. Known Problems or Issues
 
-     1. For the first scsi command sent to a device the driver increases
-        the timeout value. This gives the driver more time to perform
-        its own initialization for the board and each device. The timeout
-        value is only changed on the first scsi command for each device
-        and never thereafter. The same change is made for reset commands.
+         None
 
-  I. Credits
+  J. Credits
 
      Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
      basis for the Linux v1.3.X changes which were included in the
@@ -420,7 +454,7 @@
      Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
      in advansys_biosparam() which was fixed in the 1.3 release.
 
-  J. AdvanSys Contact Information
+  K. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
@@ -505,8 +539,8 @@
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  21
-#define ASC_LIB_SERIAL_NUMBER  88
+#define ASC_LIB_VERSION_MINOR  22
+#define ASC_LIB_SERIAL_NUMBER  89
 
 typedef unsigned char uchar;
 
@@ -581,6 +615,11 @@
 #define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
 #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
 
+#define  Asc_DvcLib_Status   int
+#define  ASC_DVCLIB_CALL_DONE     (1)
+#define  ASC_DVCLIB_CALL_FAILED   (0)
+#define  ASC_DVCLIB_CALL_ERROR    (-1)
+
 #define Lptr
 #define dosfar
 #define far
@@ -592,8 +631,8 @@
 #define outp(port, byte)    outb((byte), (port))
 #define outpw(port, word)   outw((word), (port))
 #define outpl(port, long)   outl((long), (port))
-#define ASC_MAX_SG_QUEUE	5
-#define ASC_MAX_SG_LIST		(1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE)))
+#define ASC_MAX_SG_QUEUE	7
+#define ASC_MAX_SG_LIST		SG_ALL
 
 #define CC_INIT_INQ_DISPLAY     FALSE
 #define CC_CLEAR_LRAM_SRB_PTR   FALSE
@@ -609,8 +648,6 @@
 #define CC_MEMORY_MAPPED_IO    FALSE
 #define CC_INCLUDE_EEP_CONFIG  TRUE
 #define CC_PCI_ULTRA           TRUE
-#define CC_INIT_TARGET_READ_CAPACITY    TRUE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
 #define CC_ASC_SCSI_Q_USRDEF         FALSE
 #define CC_ASC_SCSI_REQ_Q_USRDEF     FALSE
 #define CC_ASCISR_CHECK_INT_PENDING  TRUE
@@ -619,13 +656,10 @@
 #define CC_DISABLE_PCI_PARITY_INT    TRUE
 #define CC_INCLUDE_EEP_CONFIG        TRUE
 #define CC_INIT_INQ_DISPLAY          FALSE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
-#define CC_INIT_TARGET_START_UNIT       TRUE
 #define CC_PLEXTOR_VL                FALSE
 #define CC_TMP_USE_EEP_SDTR          FALSE
 #define CC_CHK_COND_REDO_SDTR        TRUE
 #define CC_SET_PCI_LATENCY_TIMER_ZERO  TRUE
-#define CC_FIX_QUANTUM_XP34301_1071  FALSE
 #define CC_DISABLE_ASYN_FIX_WANGTEK_TAPE  TRUE
 
 #define ASC_CS_TYPE  unsigned short
@@ -666,6 +700,8 @@
 #define ASC_CHIP_MAX_VER_EISA (0x47)
 #define ASC_CHIP_VER_EISA_BIT (0x40)
 #define ASC_CHIP_LATEST_VER_EISA   ( ( ASC_CHIP_MIN_VER_EISA - 1 ) + 3 )
+#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
+#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
 #define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
 #define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
 #define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
@@ -1313,6 +1349,7 @@
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
+#define ASC_DVCLIB_STATUS             0x00
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -1343,10 +1380,10 @@
 #define ASC_IOADR_DEF   ASC_IOADR_8
 #define ASC_LIB_SCSIQ_WK_SP        256
 #define ASC_MAX_SYN_XFER_NO        16
-#define ASC_SYN_XFER_NO            8
 #define ASC_SYN_MAX_OFFSET         0x0F
 #define ASC_DEF_SDTR_OFFSET        0x0F
 #define ASC_DEF_SDTR_INDEX         0x00
+#define ASC_SDTR_ULTRA_PCI_10MB_INDEX  0x02
 #define SYN_XFER_NS_0  25
 #define SYN_XFER_NS_1  30
 #define SYN_XFER_NS_2  35
@@ -1462,9 +1499,9 @@
 	ASC_SCSI_BIT_ID_TYPE no_scam;
 	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
 	uchar               max_sdtr_index;
-	uchar               res4;
+	uchar               host_init_sdtr_index;
 	ulong               drv_ptr;
-	ulong               res6;
+	ulong               uc_break;
 	ulong               res7;
 	ulong               res8;
 } ASC_DVC_VAR;
@@ -1500,7 +1537,7 @@
 #define ASC_CNTL_INIT_VERBOSE      ( ushort )0x0800
 #define ASC_CNTL_SCSI_PARITY       ( ushort )0x1000
 #define ASC_CNTL_BURST_MODE        ( ushort )0x2000
-#define ASC_CNTL_USE_8_IOP_BASE    ( ushort )0x4000
+#define ASC_CNTL_SDTR_ENABLE_ULTRA ( ushort )0x4000
 #define ASC_EEP_DVC_CFG_BEG_VL    2
 #define ASC_EEP_MAX_DVC_ADDR_VL   15
 #define ASC_EEP_DVC_CFG_BEG      32
@@ -1537,15 +1574,23 @@
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
 #define ASC_EEP_CMD_WRITE_DISABLE 0x00
 #define ASC_OVERRUN_BSIZE  0x00000048UL
+#define ASC_CTRL_BREAK_ONCE        0x0001
+#define ASC_CTRL_BREAK_STAY_IDLE   0x0002
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
+#define ASCV_BREAK_SAVED_CODE   ( ushort )0x0006
 #define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
 #define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
 #define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
 #define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
 #define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
 #define ASCV_MAX_DVC_QNG_BEG    ( ushort )0x0020
+#define ASCV_BREAK_ADDR           ( ushort )0x0028
+#define ASCV_BREAK_NOTIFY_COUNT   ( ushort )0x002A
+#define ASCV_BREAK_CONTROL        ( ushort )0x002C
+#define ASCV_BREAK_HIT_COUNT      ( ushort )0x002E
+
 #define ASCV_ASCDVC_ERR_CODE_W  ( ushort )0x0030
 #define ASCV_MCODE_CHKSUM_W   ( ushort )0x0032
 #define ASCV_MCODE_SIZE_W     ( ushort )0x0034
@@ -2052,7 +2097,11 @@
 #define ASC_NUM_BUS				4
 
 /* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((struct asc_board *) &((host)->hostdata))
+#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
+
+/* asc_board_t flags */
+#define ASC_HOST_IN_RESET		0x01
+#define ASC_HOST_IN_ABORT		0x02
 
 #define NO_ISA_DMA				0xff		/* No ISA DMA Channel Used */
 
@@ -2102,6 +2151,12 @@
 #define ASC_FRONT		1
 #define ASC_BACK		2
 
+/* asc_dequeue_list() argument */
+#define ASC_TID_ALL		(-1)
+
+/* Return non-zero, if the queue is empty. */
+#define ASC_QUEUE_EMPTY(ascq)	((ascq)->q_tidmask == 0)
+
 /* PCI configuration declarations */
 
 #define PCI_BASE_CLASS_PREDEFINED			0x00
@@ -2364,6 +2419,7 @@
 	ulong 	check_interrupt;/* # advansys_interrupt() check pending calls */
 	ulong 	interrupt;		/* # advansys_interrupt() interrupts */
 	ulong 	callback;		/* # calls asc_isr_callback() */
+	ulong 	done;			/* # calls request scsi_done */
 	/* AscExeScsiQueue() Statistics */
 	ulong 	asc_noerror;	/* # AscExeScsiQueue() ASC_NOERROR returns. */
 	ulong 	asc_busy;		/* # AscExeScsiQueue() ASC_BUSY returns. */
@@ -2374,7 +2430,7 @@
 	ulong 	cont_xfer;		/* # contiguous transfer 512-bytes */
 	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
 	ulong 	sg_elem;		/* # scatter-gather elements */
-	ulong 	sg_xfer;		/* # scatter-gather tranfer 512-bytes */
+	ulong 	sg_xfer;		/* # scatter-gather transfer 512-bytes */
 	/* Device SCSI Command Queuing Statistics */
 	ASC_SCSI_BIT_ID_TYPE queue_full;
 	ushort	queue_full_cnt[ASC_MAX_TID+1];
@@ -2385,11 +2441,12 @@
  * Request queuing structure
  */
 typedef struct asc_queue {
-	ASC_SCSI_BIT_ID_TYPE	tidmask;				  /* queue mask */
-	REQP					queue[ASC_MAX_TID+1];	  /* queue linked list */
+	ASC_SCSI_BIT_ID_TYPE	q_tidmask;				  /* queue mask */
+	REQP					q_first[ASC_MAX_TID+1];	  /* first queued request */
+	REQP					q_last[ASC_MAX_TID+1];	  /* last queued request */
 #ifdef ADVANSYS_STATS
-	short					cur_count[ASC_MAX_TID+1]; /* current queue count */
-	short					max_count[ASC_MAX_TID+1]; /* maximum queue count */
+	short					q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
+	short					q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
@@ -2400,28 +2457,25 @@
  * of the 'Scsi_Host' structure starting at the 'hostdata'
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
-struct asc_board {
-	int				 	 id;					  /* Board Id */
-	/* Asc Library */
-	ASC_DVC_VAR			 asc_dvc_var;			  /* Board configuration */
-	ASC_DVC_CFG			 asc_dvc_cfg;			  /* Device configuration */
-	/* Queued Commands */
-	asc_queue_t			 active;				  /* Active command queue */
-	asc_queue_t			 pending;		  		  /* Pending command queue */
-	/* Target Initialization */
-	ASC_SCSI_BIT_ID_TYPE init_tidmask;			  /* Target initialized mask */
-	ASC_SCSI_REQ_Q		 scsireqq;
-	ASC_CAP_INFO		 cap_info;
-	ASC_SCSI_INQUIRY	 inquiry;
-	ASCEEP_CONFIG		 eep_config;			  /* EEPROM configuration */
+typedef struct asc_board {
+	int				 	 id;				/* Board Id */
+	uint				 flags;				/* Board flags */
+	ASC_DVC_VAR			 asc_dvc_var;		/* Board configuration */
+	ASC_DVC_CFG			 asc_dvc_cfg;		/* Device configuration */
+	asc_queue_t			 active;			/* Active command queue */
+	asc_queue_t			 waiting;		  	/* Waiting command queue */
+	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
+	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
+	asc_queue_t			 scsi_done_q;		/* Completion command queue */
+	ulong				 reset_jiffies;		/* Saved time of last reset */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 	/* /proc/scsi/advansys/[0...] */
-	char				 *prtbuf;				  /* Statistics Print Buffer */
+	char				 *prtbuf;			/* Statistics Print Buffer */
 #endif /* version >= v1.3.0 */
 #ifdef ADVANSYS_STATS
-	struct asc_stats	 asc_stats;				  /* Board statistics */
+	struct asc_stats	 asc_stats;			/* Board statistics */
 #endif /* ADVANSYS_STATS */
-};
+} asc_board_t;
 
 /*
  * PCI configuration structures
@@ -2494,12 +2548,22 @@
 STATIC int asc_board_count = 0;
 STATIC struct Scsi_Host	*asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
 
-/* Global list of commands needing done function. */
-STATIC Scsi_Cmnd *asc_scsi_done = NULL;
-
 /* Overrun buffer shared between all boards. */
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
+/*
+ * Global structures used for device initialization.
+ */
+STATIC ASC_SCSI_REQ_Q	 asc_scsireqq = { { 0 } };
+STATIC ASC_CAP_INFO		 asc_cap_info = { 0 };
+STATIC ASC_SCSI_INQUIRY	 asc_inquiry = { { 0 } };
+
+/*
+ * Global structures required to issue a command.
+ */
+STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
+STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+
 /* List of supported bus types. */
 STATIC ushort asc_bus[ASC_NUM_BUS] = {
 	ASC_IS_ISA,
@@ -2549,6 +2613,7 @@
 												Scsi_Device *);
 #endif /* version >= v1.3.89 */
 STATIC void 		advansys_command_done(Scsi_Cmnd *);
+STATIC void 		asc_scsi_done_list(Scsi_Cmnd *);
 STATIC int 			asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC void 		asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC int 			asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
@@ -2561,11 +2626,13 @@
 STATIC void 		asc_put_cfg_byte(PCI_DATA *, uchar);
 void				asc_enqueue(asc_queue_t *, REQP, int);
 REQP 				asc_dequeue(asc_queue_t *, int);
+REQP 				asc_dequeue_list(asc_queue_t *, REQP *, int);
 int					asc_rmqueue(asc_queue_t *, REQP);
 int					asc_isqueued(asc_queue_t *, REQP);
 void				asc_execute_queue(asc_queue_t *);
 STATIC int			asc_prt_board_devices(struct Scsi_Host *, char *, int);
 STATIC int			asc_prt_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int			asc_prt_driver_conf(struct Scsi_Host *, char *, int);
 STATIC int			asc_prt_board_info(struct Scsi_Host *, char *, int);
 STATIC int			asc_proc_copy(off_t, off_t, char *, int , char *, int);
 STATIC int			asc_prt_line(char *, int, char *fmt, ...);
@@ -2618,7 +2685,7 @@
 				   int hostno, int inout)
 {
 	struct Scsi_Host	*shp;
-	struct asc_board	*boardp;
+	asc_board_t 		*boardp;
 	int					i;
 	char				*cp;
 	int					cplen;
@@ -2738,6 +2805,22 @@
 	advoffset += cplen;
 	curbuf += cnt;
 
+	/*
+	 * Display driver configuration and information for the board.
+	 */
+	cp = boardp->prtbuf;
+	cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
+
 #ifdef ADVANSYS_STATS
 	/*
 	 * Display driver statistics for the board.
@@ -2800,7 +2883,7 @@
 	int					iop;
 	int					bus;
 	struct Scsi_Host	*shp;
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					ioport = 0;
 	int					share_irq = FALSE;
@@ -2966,14 +3049,14 @@
 			 * initialize it.
 			 */
 			ASC_DBG(2, "advansys_detect: scsi_register()\n");
-			shp = scsi_register(tpnt, sizeof(struct asc_board));
+			shp = scsi_register(tpnt, sizeof(asc_board_t));
 
 			/* Save a pointer to the Scsi_host of each board found. */
 			asc_host[asc_board_count++] = shp;
 
 			/* Initialize private per board data */
 			boardp = ASC_BOARDP(shp);
-			memset(boardp, 0, sizeof(struct asc_board));
+			memset(boardp, 0, sizeof(asc_board_t));
 			boardp->id = asc_board_count - 1;
 			asc_dvc_varp = &boardp->asc_dvc_var;
 			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
@@ -2984,7 +3067,7 @@
 			if ((boardp->prtbuf =
 				kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
 				ASC_PRINT3(
-"advansys_detect: Board %d: kmalloc(%d, %d) returned NULL\n",
+"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
 					boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
 				scsi_unregister(shp);
 				asc_board_count--;
@@ -3021,7 +3104,7 @@
 				break;
 			default:
 				ASC_PRINT2(
-"advansys_detect: Board %d: unknown adapter type: %d",
+"advansys_detect: board %d: unknown adapter type: %d",
 					boardp->id, asc_dvc_varp->bus_type);
 				shp->unchecked_isa_dma = TRUE;
 				share_irq = FALSE;
@@ -3042,38 +3125,38 @@
 				break;
 			case ASC_WARN_IO_PORT_ROTATE:
 				ASC_PRINT1(
-"AscInitGetConfig: Board: %d: I/O port address modified\n",
+"AscInitGetConfig: board %d: I/O port address modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_AUTO_CONFIG:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
 					boardp->id);
 				break;
 			case ASC_WARN_EEPROM_CHKSUM:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: EEPROM checksum error\n",
+"AscInitGetConfig: board %d: EEPROM checksum error\n",
 					boardp->id);
 				break;
 			case ASC_WARN_IRQ_MODIFIED:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: IRQ modified\n",
+"AscInitGetConfig: board %d: IRQ modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_CMD_QNG_CONFLICT:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: tag queuing enabled w/o disconnects\n",
+"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
 					boardp->id);
 				break;
 			default:
 				ASC_PRINT2(
-"AscInitGetConfig: Board %d: unknown warning: %x\n",
+"AscInitGetConfig: board %d: unknown warning: %x\n",
 					boardp->id, ret);
 				break;
 			}
 			if (asc_dvc_varp->err_code != 0) {
 				ASC_PRINT3(
-"AscInitGetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3117,38 +3200,38 @@
 				break;
 			case ASC_WARN_IO_PORT_ROTATE:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port address modified\n",
+"AscInitSetConfig: board %d: I/O port address modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_AUTO_CONFIG:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
 					boardp->id);
 				break;
 			case ASC_WARN_EEPROM_CHKSUM:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: EEPROM checksum error\n",
+"AscInitSetConfig: board %d: EEPROM checksum error\n",
 					boardp->id);
 				break;
 			case ASC_WARN_IRQ_MODIFIED:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: IRQ modified\n",
+"AscInitSetConfig: board %d: IRQ modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_CMD_QNG_CONFLICT:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: tag queuing w/o disconnects\n",
+"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
 					boardp->id);
 				break;
 			default:
 				ASC_PRINT2(
-"AscInitSetConfig: Board %d: unknown warning: %x\n",
+"AscInitSetConfig: board %d: unknown warning: %x\n",
 					boardp->id, ret);
 				break;
 			}
 			if (asc_dvc_varp->err_code != 0) {
 				ASC_PRINT3(
-"AscInitSetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3168,6 +3251,16 @@
 				shp->irq = asc_dvc_varp->irq_no;
 			}
 
+			/*
+			 * One host supports one channel. There are two different
+			 * hosts for each channel of a dual channel board.
+			 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+			shp->max_channel = 0;
+#endif /* version >= v1.3.89 */
+			shp->max_id = ASC_MAX_TID + 1;
+			shp->max_lun = ASC_MAX_LUN + 1;
+
 			shp->io_port = asc_dvc_varp->iop_base;
 			shp->n_io_port = ASC_IOADR_GAP;
 			shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
@@ -3196,7 +3289,6 @@
 			shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
 #endif /* version >= v1.3.89 */
 
-			
 			/*
 			 * Maximum number of scatter-gather elements adapter can handle.
 			 *
@@ -3206,8 +3298,27 @@
 #ifdef MODULE
 			shp->sg_tablesize = 8;
 #else /* MODULE */
-			shp->sg_tablesize = ASC_MAX_SG_LIST;
+			/*
+			 * Allow two commands with 'sg_tablesize' scatter-gather
+			 * elements to be executed simultaneously. This value is
+			 * the theoretical hardware limit. It may be decreased
+			 * below.
+			 */
+			shp->sg_tablesize =
+				(((asc_dvc_varp->max_total_qng - 2) / 2) *
+				ASC_SG_LIST_PER_Q) + 1;
 #endif /* MODULE */
+
+			/*
+			 * The value of 'sg_tablesize' can not exceed the SCSI
+			 * mid-level driver definition of SG_ALL. SG_ALL also
+			 * must not be exceeded, because it is used to define the
+			 * size of the scatter-gather table in 'struct asc_sg_head'.
+			 */
+			if (shp->sg_tablesize > SG_ALL) {
+				shp->sg_tablesize = SG_ALL;
+			}
+
 			ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
 				shp->sg_tablesize);
 
@@ -3231,7 +3342,7 @@
 				shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
 				if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
 					ASC_PRINT3(
-"advansys_detect: Board %d: request_dma() %d failed %d\n",
+"advansys_detect: board %d: request_dma() %d failed %d\n",
 						boardp->id, shp->dma_channel, ret);
 					release_region(shp->io_port, shp->n_io_port);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3255,7 +3366,7 @@
 							"advansys", boardp)) != 0) {
 #endif /* version >= v1.3.70 */
 				ASC_PRINT2(
-"advansys_detect: Board %d: request_irq() failed %d\n",
+"advansys_detect: board %d: request_irq() failed %d\n",
 					boardp->id, ret);
 				release_region(shp->io_port, shp->n_io_port);
 				if (shp->dma_channel != NO_ISA_DMA) {
@@ -3275,7 +3386,7 @@
 			ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
 			if (AscInitAsc1000Driver(asc_dvc_varp)) {
 				ASC_PRINT3(
-"AscInitAsc1000Driver: Board %d error: init_state %x, err_code %x\n",
+"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 				release_region(shp->io_port, shp->n_io_port);
@@ -3309,7 +3420,7 @@
 int
 advansys_release(struct Scsi_Host *shp)
 {
-	struct asc_board	*boardp;
+	asc_board_t	*boardp;
 
 	ASC_DBG(1, "advansys_release: begin\n");
 	boardp = ASC_BOARDP(shp);
@@ -3344,18 +3455,23 @@
 const char *
 advansys_info(struct Scsi_Host *shp)
 {
-	static char 		info[ASC_INFO_SIZE];
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	char				*busname;
+	static char 	info[ASC_INFO_SIZE];
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	char			*busname;
 
 	boardp = ASC_BOARDP(shp);
 	asc_dvc_varp = &boardp->asc_dvc_var;
 	ASC_DBG(1, "advansys_info: begin\n");
 	if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+		if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+			busname = "ISA PnP";
+		} else {
+			busname = "ISA";
+		}
 		sprintf(info,
-			"AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u",
-			ASC_VERSION, boardp->asc_dvc_var.max_total_qng,
+			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u",
+			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
 			(unsigned) shp->base, shp->io_port,
 			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
 	} else {
@@ -3364,16 +3480,21 @@
 		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
 			busname = "EISA";
 		} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-			busname = "PCI";
+			if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+				== ASC_IS_PCI_ULTRA) {
+				busname = "PCI Ultra";
+			} else {
+				busname = "PCI";
+			}
 		} else {
 			busname = "?";
 			ASC_PRINT2(
-"advansys_info: Board %d: unknown bus type %d\n",
+"advansys_info: board %d: unknown bus type %d\n",
 				boardp->id, asc_dvc_varp->bus_type);
 		}
 		/* No DMA channel for non-ISA busses. */
 		sprintf(info,
-			"AdvanSys SCSI %s: %s (%u CDB): BIOS %X, IO %X-%X, IRQ %u",
+			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
 			(unsigned) shp->base, shp->io_port,
 			shp->io_port + (shp->n_io_port - 1), shp->irq);
@@ -3416,52 +3537,88 @@
 int
 advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 {
-	struct Scsi_Host		*shp;
-	struct asc_board		*boardp;
-	int						flags = 0;
-	int						interrupts_disabled;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
+	int					flags;
+	Scsi_Cmnd			*done_scp;
 
 	shp = scp->host;
 	boardp = ASC_BOARDP(shp);
 	ASC_STATS(shp, queuecommand);
 
 	/*
-	 * If there are any pending commands for this board before trying
-	 * to execute them, disable interrupts to preserve request ordering.
-	 *
-	 * The typical case will be no pending commands and interrupts
-	 * not disabled.
+	 * Disable interrupts to preserve request ordering and provide
+	 * mutually exclusive access to global structures used to initiate
+	 * a request.
 	 */
-	if (boardp->pending.tidmask == 0) {
-		interrupts_disabled = ASC_FALSE;
-	} else {
-		/* Disable interrupts */
-		interrupts_disabled = ASC_TRUE;
-		save_flags(flags);
-		cli();
-		ASC_DBG1(1, "advansys_queuecommand: asc_execute_queue() %x\n",
-			boardp->pending.tidmask);
-		asc_execute_queue(&boardp->pending);
-	}
+	save_flags(flags);
+	cli();
 
 	/*
-	 * Save the function pointer to Linux mid-level 'done' function and
-	 * execute the command.
+	 * Block new commands while handling a reset or abort request.
 	 */
-	scp->scsi_done = done;
-	if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) {
-		if (interrupts_disabled == ASC_FALSE) {
-			save_flags(flags);
-			cli();
-			interrupts_disabled = ASC_TRUE;
+	if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+		if (boardp->flags & ASC_HOST_IN_RESET) {
+			ASC_DBG1(1,
+				"advansys_queuecommand: scp %x blocked for reset request\n",
+				(unsigned) scp);
+			scp->result = HOST_BYTE(DID_RESET);
+		} else {
+			ASC_DBG1(1,
+				"advansys_queuecommand: scp %x blocked for abort request\n",
+				(unsigned) scp);
+			scp->result = HOST_BYTE(DID_ABORT);
 		}
-		asc_enqueue(&boardp->pending, scp, ASC_BACK);
-	}
 
-	if (interrupts_disabled == ASC_TRUE) {
+		/*
+		 * Add blocked requests to the board's 'scsi_done_q'. The queued
+		 * requests will be completed at the end of the abort or reset
+		 * handling.
+		 */
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		restore_flags(flags);
+		return 0;
+	}
+
+	/*
+	 * Attempt to execute any waiting commands for the board.
+	 */
+	if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+		ASC_DBG(1,
+			"advansys_queuecommand: before asc_execute_queue() waiting\n");
+		asc_execute_queue(&boardp->waiting);
+	}
+
+	/*
+	 * Save the function pointer to Linux mid-level 'done' function
+	 * and attempt to execute the command.
+	 *
+	 * If ASC_ERROR is returned the request has been added to the
+	 * board's 'active' queue and will be completed by the interrupt
+	 * handler.
+	 *
+	 * If ASC_BUSY is returned add the request to the board's per
+	 * target waiting list.
+	 * 
+	 * If an error occurred, the request will have been placed on the
+	 * board's 'scsi_done_q' and must be completed before returning.
+	 */
+	scp->scsi_done = done;
+	switch (asc_execute_scsi_cmnd(scp)) {
+	case ASC_NOERROR:
+		break;
+	case ASC_BUSY:
+		asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+		break;
+	case ASC_ERROR:
+	default:
+		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		/* Interrupts could be enabled here. */
+		asc_scsi_done_list(done_scp);
+		break;
 	}
 
+	restore_flags(flags);
 	return 0;
 }
 
@@ -3473,49 +3630,70 @@
 int
 advansys_abort(Scsi_Cmnd *scp)
 {
-	struct asc_board	*boardp;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	int					abort;
-	int					ret;
+	int					status = ASC_FALSE;
+	int					abort_do_done = ASC_FALSE;
+	Scsi_Cmnd			*done_scp;
+	int					ret = ASC_ERROR;
 
 	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
-	ASC_STATS(scp->host, abort);
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+#ifdef ADVANSYS_STATS
+	if (scp->host != NULL) {
+		ASC_STATS(scp->host, abort);
+	}	
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
 		ret = SCSI_ABORT_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
-	if (scp->host == NULL) {
+	if ((shp = scp->host) == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_ABORT_ERROR;
+	} else if ((boardp = ASC_BOARDP(shp))->flags & 
+				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+		ASC_PRINT2(
+"advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
+			boardp->id, boardp->flags);
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_ABORT_ERROR;
 	} else {
-		boardp = ASC_BOARDP(scp->host);
-		if (asc_rmqueue(&boardp->pending, scp) == ASC_TRUE) {
+		/* Set abort flag to avoid nested reset or abort requests. */
+		boardp->flags |= ASC_HOST_IN_ABORT;
+
+		if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			/*
-		 	 * If asc_rmqueue() found the command on the pending
-			 * queue, it had not been sent to the Asc Library.
-			 * After the queue is removed, no other handling is required.
+		 	 * If asc_rmqueue() found the command on the waiting
+			 * queue, it had not been sent to the device. After
+			 * the queue is removed, no other handling is required.
 		 	 */
+			ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
+				(unsigned) scp);
 			scp->result = HOST_BYTE(DID_ABORT);
 			ret = SCSI_ABORT_SUCCESS;
 		} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
 			/*
 		 	 * If asc_isqueued() found the command on the active
-			 * queue, it has been sent to the Asc Library. The
-			 * command should be returned through the interrupt
-			 * handler after calling AscAbortSRB().
+			 * queue, it has been sent to the device. The command
+			 * should be returned through the interrupt handler after
+			 * calling AscAbortSRB().
 		 	 */
 			asc_dvc_varp = &boardp->asc_dvc_var;
 			scp->result = HOST_BYTE(DID_ABORT);
-			/* Must enable interrupts for AscAbortSRB() */
-			sti();
-			switch (abort = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+
+			sti(); /* Enable interrupts for AscAbortSRB(). */
+			ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
+				(unsigned) scp);
+			switch (status = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
 			case ASC_TRUE:
 				/* asc_isr_callback() will be called */
 				ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -3533,25 +3711,69 @@
 				break;
 			}
 			cli();
+
 			/*
 			 * If the abort failed, remove the request from the
 			 * active list and complete it.
 			 */
-			if (abort != ASC_TRUE) {
+			if (status != ASC_TRUE) {
 				if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
 					scp->result = HOST_BYTE(DID_ABORT);
-					scp->scsi_done(scp);
+					abort_do_done = ASC_TRUE;
 				}
 			}
+
 		} else {
 			/*
-			 * The command was not found on the active or pending queues.
+			 * The command was not found on the active or waiting queues.
 			 */
 			ret = SCSI_ABORT_NOT_RUNNING;
 		}
+
+		/* Clear abort flag. */
+		boardp->flags &= ~ASC_HOST_IN_ABORT;
+
+		/*
+		 * Because the ASC_HOST_IN_ABORT flag causes both
+		 * 'advansys_interrupt' and 'asc_isr_callback' to
+		 * queue requests to the board's 'scsi_done_q' and
+		 * prevents waiting commands from being executed,
+		 * these queued requests must be handled here.
+		 */
+		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+
+		/*
+		 * Start any waiting commands for the board.
+		 */
+		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+			asc_execute_queue(&boardp->waiting);
+		}
+
+		/* Interrupts could be enabled here. */
+
+		/*
+		 * If needed, complete the aborted request.
+		 */
+		if (abort_do_done == ASC_TRUE) {
+			ASC_STATS(scp->host, done);
+			scp->scsi_done(scp);
+		}
+
+		/*
+		 * It is possible for the request done function to re-enable
+		 * interrupts without confusing the driver. But here interrupts
+		 * aren't enabled until all requests have been completed.
+		 */
+		asc_scsi_done_list(done_scp);
 	}
-	restore_flags(flags);
+
 	ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
+
+	/* Re-enable interrupts, if they were enabled on entry. */
+	restore_flags(flags);
+
+	ASC_ASSERT(ret != ASC_ERROR);
 	return ret;
 }
 
@@ -3567,44 +3789,74 @@
 advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
 #endif /* version >= v1.3.89 */
 {
-	struct asc_board	*boardp;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	Scsi_Cmnd			*tscp;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	Scsi_Cmnd			*done_scp = NULL, *last_scp = NULL;
+	Scsi_Cmnd			*tscp, *new_last_scp;
 	int					scp_found = ASC_FALSE;
-#endif /* version >= v1.3.89 */
-	int					i;
-	int					ret;
+	int 				device_reset = ASC_FALSE;
+	int					status;
+	int					target;
+	int					ret = ASC_ERROR;
 
 	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
-	ASC_STATS(scp->host, reset);
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+#ifdef ADVANSYS_STATS
+	if (scp->host != NULL) {
+		ASC_STATS(scp->host, reset);
+	}	
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
 		ret = SCSI_RESET_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
-	if (scp->host == NULL) {
+	if ((shp = scp->host) == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_RESET_ERROR;
+	} else if ((boardp = ASC_BOARDP(shp))->flags & 
+				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+		ASC_PRINT2(
+"advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
+			boardp->id, boardp->flags);
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_RESET_ERROR;
+	} else if (jiffies >= boardp->reset_jiffies &&
+			   jiffies < (boardp->reset_jiffies + (10 * HZ))) {
+		/*
+		 * Don't allow a reset to be attempted within 10 seconds
+		 * of the last reset.
+		 *
+		 * If 'jiffies' wrapping occurs, the reset request will go
+		 * through, because a wrapped 'jiffies' would not pass the
+		 * test above.
+		 */
+		ASC_DBG(1,
+			"advansys_reset: reset within 10 sec of last reset ignored\n");
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
 	} else {
-		boardp = ASC_BOARDP(scp->host);
+		/* Set reset flag to avoid nested reset or abort requests. */
+		boardp->flags |= ASC_HOST_IN_RESET;
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		/*
-	 	 * If the request is on the target pending or active queue,
-		 * note that it was found.
+	 	 * If the request is on the target waiting or active queue,
+		 * note that it was found and remove it from its queue.
 		 */
-		if ((asc_isqueued(&boardp->pending, scp) == ASC_TRUE) ||
-		    (asc_isqueued(&boardp->active, scp) == ASC_TRUE)) {
+		if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+			ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
+			scp_found = ASC_TRUE;
+		} else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
+			ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
 			scp_found = ASC_TRUE;
 		}
-#endif /* version >= v1.3.89 */
 
 		/*
 		 * If the suggest reset bus flags are set, reset the bus.
@@ -3617,85 +3869,192 @@
 #endif /* version >= v1.3.89 */
 
 			/*
-			 * Done all pending requests for all targets with DID_RESET.
-			 */
-			for (i = 0; i <= ASC_MAX_TID; i++) {
-				while ((tscp = asc_dequeue(&boardp->pending, i)) != NULL) {
-					tscp->result = HOST_BYTE(DID_RESET);
-					tscp->scsi_done(tscp);
-				}
-			}
-
-			/*
 			 * Reset the target's SCSI bus.
 			 */
+			ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
 			sti();	/* Enable interrupts for AscResetSB(). */
-			switch (AscResetSB(asc_dvc_varp)) {
+			status = AscResetSB(asc_dvc_varp);
+			cli();
+			switch (status) {
 			case ASC_TRUE:
-				ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+				ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
 				ret = SCSI_RESET_SUCCESS;
 				break;
 			case ASC_ERROR:
 			default:
-				ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+				ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
 				ret = SCSI_RESET_ERROR;
 				break;
 			}
-			cli();
 
-			/*
-			 * Done all active requests for all targets with DID_RESET.
-			 */
-			for (i = 0; i <= ASC_MAX_TID; i++) {
-				while ((tscp = asc_dequeue(&boardp->active, i)) != NULL) {
-					tscp->result = HOST_BYTE(DID_RESET);
-					tscp->scsi_done(tscp);
-				}
-			}
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		} else {
 			/*
-			 * Done all pending requests for the target with DID_RESET.
+			 * Reset the specified device. If the device reset fails,
+			 * then reset the SCSI bus.
 			 */
-			while ((tscp = asc_dequeue(&boardp->pending, scp->target))
-					!= NULL) {
-				tscp->result = HOST_BYTE(DID_RESET);
-				tscp->scsi_done(tscp);
-			}
 
-			sti();	/* Enabled interrupts for AscResetDevice(). */
-			ASC_DBG(1, "advansys_reset: AscResetDevice()\n");
-			(void) AscResetDevice(asc_dvc_varp, scp->target);
+			ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n",
+				scp->target);
+			sti();	/* Enable interrupts for AscResetDevice(). */
+			status = AscResetDevice(asc_dvc_varp, scp->target);
 			cli();
 
 			/*
-			 * Done all active requests for the target with DID_RESET.
+			 * If the device has been reset, try to initialize it.
 			 */
-			while ((tscp = asc_dequeue(&boardp->active, scp->target))
-					!= NULL) {
-				tscp->result = HOST_BYTE(DID_RESET);
-				tscp->scsi_done(tscp);
+			if (status == ASC_TRUE) {
+				status = asc_init_dev(asc_dvc_varp, scp);
+			}
+
+			switch (status) {
+			case ASC_TRUE:
+				ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
+				device_reset = ASC_TRUE;
+				ret = SCSI_RESET_SUCCESS;
+				break;
+			case ASC_ERROR:
+			default:
+				ASC_DBG(1,
+"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
+				sti();	/* Enable interrupts for AscResetSB(). */
+				status = AscResetSB(asc_dvc_varp);
+				cli();
+				switch (status) {
+				case ASC_TRUE:
+					ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+					ret = SCSI_RESET_SUCCESS;
+					break;
+				case ASC_ERROR:
+				default:
+					ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+					ret = SCSI_RESET_ERROR;
+					break;
+				}
+				break;
 			}
 		}
 #endif /* version >= v1.3.89 */
 
+		/*
+		 * Because the ASC_HOST_IN_RESET flag causes both
+		 * 'advansys_interrupt' and 'asc_isr_callback' to
+		 * queue requests to the board's 'scsi_done_q' and
+		 * prevents waiting commands from being executed,
+		 * these queued requests must be handled here.
+		 */
+		done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+									ASC_TID_ALL);
+
+		/*
+		 * If a device reset was performed dequeue all waiting
+		 * and active requests for the device and set the request
+		 * status to DID_RESET.
+		 *
+		 * If a SCSI bus reset was performed dequeue all waiting
+		 * and active requests for all devices and set the request
+		 * status to DID_RESET.
+		 */
+		if (device_reset == ASC_TRUE) {
+			target = scp->target;
+		} else {
+			target = ASC_TID_ALL;
+		}
+
+		/*
+		 * Add active requests to 'done_scp' and set the request status
+		 * to DID_RESET.
+		 */
+		if (done_scp == NULL) {
+			done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
+			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+		} else {
+			ASC_ASSERT(last_scp != NULL);
+			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
+				&new_last_scp, target);
+			if (new_last_scp != NULL) {
+				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+					tscp->result = HOST_BYTE(DID_RESET);
+				}
+				last_scp = new_last_scp;
+			}
+		}
+
+		/*
+		 * Add waiting requests to 'done_scp' and set the request status
+		 * to DID_RESET.
+		 */
+		if (done_scp == NULL) {
+			done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
+			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+		} else {
+			ASC_ASSERT(last_scp != NULL);
+			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
+				&new_last_scp, target);
+			if (new_last_scp != NULL) {
+				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+					tscp->result = HOST_BYTE(DID_RESET);
+				}
+				last_scp = new_last_scp;
+			}
+		}
+
+		/* Save the time of the most recently completed reset. */
+		boardp->reset_jiffies = jiffies;
+
+		/* Clear reset flag. */
+		boardp->flags &= ~ASC_HOST_IN_RESET;
+
+		/*
+		 * Start any waiting commands for the board.
+		 */
+		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+			asc_execute_queue(&boardp->waiting);
+		}
+
+		/* Interrupts could be enabled here. */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		/*
-		 * If the command was not on the active or pending request
-		 * queues and the SCSI_RESET_SYNCHRONOUS flag is set, then
-		 * done the command now. If the command had been on the
-		 * active or pending request queues it would have already
-		 * been completed.
+		 * If the command was found on the active or waiting request
+		 * queues or if the the SCSI_RESET_SYNCHRONOUS flag is set,
+		 * then done the command now.
 		 */
-		if (scp_found == ASC_FALSE && (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
+		if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
 			scp->result = HOST_BYTE(DID_RESET);
-			scp->scsi_done(tscp);
+			ASC_STATS(scp->host, done);
+			scp->scsi_done(scp);
+		}
+#else /* version >= v1.3.89 */
+		if (scp_found == ASC_TRUE) {
+			scp->result = HOST_BYTE(DID_RESET);
+			ASC_STATS(scp->host, done);
+			scp->scsi_done(scp);
 		}
 #endif /* version >= v1.3.89 */
 		ret = SCSI_RESET_SUCCESS;
+
+		/*
+		 * It is possible for the request done function to re-enable
+		 * interrupts without confusing the driver. But here interrupts
+		 * aren't enabled until requests have been completed.
+		 */
+		asc_scsi_done_list(done_scp);
 	}
-	restore_flags(flags);
+
 	ASC_DBG1(1, "advansys_reset: ret %d", ret);
+
+	/* Re-enable interrupts, if they were enabled on entry. */
+	restore_flags(flags);
+
+	ASC_ASSERT(ret != ASC_ERROR);
 	return ret;
 }
 
@@ -3826,10 +4185,10 @@
  * First-level interrupt handler.
  *
  * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting
- * adapter's struct asc_board. Because all boards are currently checked
+ * adapter's asc_board_t. Because all boards are currently checked
  * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id'
- * could be used to identify an interrupt passed to the AdvanSys driver
- * but actually for a device sharing an interrupt with an AdvanSys adapter.
+ * could be used to identify an interrupt passed to the AdvanSys driver,
+ * which is for a device sharing an interrupt with an AdvanSys adapter.
  */
 STATIC void
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
@@ -3838,12 +4197,13 @@
 advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif /* version >= v1.3.70 */
 {
-	int			i;
-	int			flags;
-	Scsi_Cmnd	*scp;
-	Scsi_Cmnd	*tscp;
+	int				flags;
+	int				i;
+	asc_board_t		*boardp;
+	Scsi_Cmnd		*done_scp = NULL, *last_scp = NULL;
+	Scsi_Cmnd		*new_last_scp;
 
-	/* Disable interrupts, if the aren't already disabled. */
+	/* Disable interrupts, if they aren't already disabled. */
 	save_flags(flags);
 	cli();
 
@@ -3854,31 +4214,57 @@
 	 */
 	for (i = 0; i < asc_board_count; i++) {
 		ASC_STATS(asc_host[i], check_interrupt);
+		boardp = ASC_BOARDP(asc_host[i]);
 		while (AscIsIntPending(asc_host[i]->io_port)) {
 			ASC_STATS(asc_host[i], interrupt);
 			ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
-			AscISR(&ASC_BOARDP(asc_host[i])->asc_dvc_var);
+			AscISR(&boardp->asc_dvc_var);
+		}
+
+		/*
+		 * Start waiting requests and create a list of completed requests.
+		 * 
+		 * If a reset or abort request is being performed for the board,
+		 * the reset or abort handler will complete pending requests after
+		 * it has completed.
+		 */
+    	if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
+			/* Start any waiting commands for the board. */
+			if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+				ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+				asc_execute_queue(&boardp->waiting);
+			}
+
+		 	/*
+			 * Add to the list of requests that must be completed.
+			 */
+			if (done_scp == NULL) {
+				done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+					ASC_TID_ALL);
+			} else {
+				ASC_ASSERT(last_scp != NULL);
+				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q,
+					&new_last_scp, ASC_TID_ALL);
+				if (new_last_scp != NULL) {
+					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+					last_scp = new_last_scp;
+				}
+			}
 		}
 	}
 
+	/* Interrupts could be enabled here. */
+
 	/*
-	 * While interrupts are still disabled save the list of requests that
-	 * need their done function called. After re-enabling interrupts call
-	 * the done function which may re-enable interrupts anyway.
+	 * It is possible for the request done function to re-enable
+	 * interrupts without confusing the driver. But here interrupts
+	 * aren't enabled until all requests have been completed.
 	 */
-	if ((scp = asc_scsi_done) != NULL) {
-		asc_scsi_done = NULL;
-	}
+	asc_scsi_done_list(done_scp);
 
 	/* Re-enable interrupts, if they were enabled on entry. */
 	restore_flags(flags);
 
-	while (scp) {
-		tscp = (Scsi_Cmnd *) scp->host_scribble;
-		scp->scsi_done(scp);
-		scp = tscp;
-	}
-
 	ASC_DBG(1, "advansys_interrupt: end\n");
 	return;
 }
@@ -3891,8 +4277,8 @@
 STATIC void
 advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
 {
-	Scsi_Device			*device;
-	struct asc_board	*boardp;
+	Scsi_Device		*device;
+	asc_board_t		*boardp;
 
 	boardp = ASC_BOARDP(shp);
 	for (device = devicelist; device != NULL; device = device->next) {
@@ -3918,6 +4304,27 @@
 }
 
 /*
+ * Complete all requests on the singly linked list pointed
+ * to by 'scp'.
+ *
+ * Interrupts can be enabled on entry.
+ */
+STATIC void
+asc_scsi_done_list(Scsi_Cmnd *scp)
+{
+	Scsi_Cmnd	*tscp;
+
+	while (scp != NULL) {
+		tscp = REQPNEXT(scp);
+		REQPNEXT(scp) = NULL;
+		ASC_STATS(scp->host, done);
+		scp->scsi_done(scp);
+		scp = tscp;
+	}
+	return;
+}
+
+/*
  * Execute a single 'Scsi_Cmnd'.
  *
  * The function 'done' is called when the request has been completed.
@@ -3952,20 +4359,21 @@
  *  scsi_done - used to save caller's done function
  * 	host_scribble - used for pointer to another Scsi_Cmnd
  *
- * If this function returns ASC_NOERROR or ASC_ERROR the done
- * function has been called. If ASC_BUSY is returned the request
- * must be enqueued by the caller and re-tried later.
+ * If this function returns ASC_NOERROR or ASC_ERROR the request
+ * has been enqueued on the board's 'scsi_done_q' and must be
+ * completed by the caller.
+ *
+ * If ASC_BUSY is returned the request must be enqueued by the
+ * caller and re-tried later.
  */
 STATIC int
 asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 {
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	ASC_SCSI_Q			scsiq;
-	ASC_SG_HEAD			sghead;
-	int					flags;
-	int					ret;
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	int				ret;
 
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
 		(unsigned) scp, (unsigned) scp->scsi_done);
 
@@ -3979,30 +4387,34 @@
 	if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
 		if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
 			scp->result = HOST_BYTE(DID_BAD_TARGET);
-			scp->scsi_done(scp);
+			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 		boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
 	}
 
-	memset(&scsiq, 0, sizeof(ASC_SCSI_Q));
+	/*
+	 * Mutually exclusive access is required to 'asc_scsi_q' and
+	 * 'asc_sg_head' until after the request is started.
+	 */
+	memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
 
 	/*
 	 * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
 	 */
-	scsiq.q2.srb_ptr = (ulong) scp;
+	asc_scsi_q.q2.srb_ptr = (ulong) scp;
 
 	/*
 	 * Build the ASC_SCSI_Q request.
 	 */
-	scsiq.cdbptr = &scp->cmnd[0];
-	scsiq.q2.cdb_len = scp->cmd_len;
-	scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	scsiq.q1.target_lun = scp->lun;
-	scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-	scsiq.q1.sense_addr = (ulong) &scp->sense_buffer[0];
-	scsiq.q1.sense_len = sizeof(scp->sense_buffer);
-	scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+	asc_scsi_q.cdbptr = &scp->cmnd[0];
+	asc_scsi_q.q2.cdb_len = scp->cmd_len;
+	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	asc_scsi_q.q1.target_lun = scp->lun;
+	asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+	asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
 
 	/*
 	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
@@ -4014,12 +4426,12 @@
 		 */
 		ASC_STATS(scp->host, cont_cnt);
  		/* request_buffer is already a real address. */
-		scsiq.q1.data_addr = (ulong) scp->request_buffer;
-		scsiq.q1.data_cnt = scp->request_bufflen;
+		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
 		ASC_STATS_ADD(scp->host, cont_xfer,
 					  ASC_CEILING(scp->request_bufflen, 512));
-		scsiq.q1.sg_queue_cnt = 0;
-		scsiq.sg_head = NULL;
+		asc_scsi_q.q1.sg_queue_cnt = 0;
+		asc_scsi_q.sg_head = NULL;
 	} else {
 		/*
 		 * CDB scatter-gather request list.
@@ -4027,11 +4439,12 @@
 		int					sgcnt;
 		struct scatterlist	*slp;
 
-		if (scp->use_sg > ASC_MAX_SG_LIST) {
-			ASC_PRINT3("asc_execute_scsi_cmnd: Board %d: use_sg %d > %d\n",
-				boardp->id, scp->use_sg, ASC_MAX_SG_LIST);
+		if (scp->use_sg > scp->host->sg_tablesize) {
+			ASC_PRINT3(
+"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
+				boardp->id, scp->use_sg, scp->host->sg_tablesize);
 			scp->result = HOST_BYTE(DID_ERROR);
-			scp->scsi_done(scp);
+			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 
@@ -4041,40 +4454,37 @@
 		 * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
 		 * to point to it.
 		 */
-		memset(&sghead, 0, sizeof(ASC_SG_HEAD));
+		memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
 
-		scsiq.q1.cntl |= QC_SG_HEAD;
-		scsiq.sg_head = &sghead;
-		scsiq.q1.data_cnt = 0;
-		scsiq.q1.data_addr = 0;
-		sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg;
-		ASC_STATS_ADD(scp->host, sg_elem, sghead.entry_cnt);
+		asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+		asc_scsi_q.sg_head = &asc_sg_head;
+		asc_scsi_q.q1.data_cnt = 0;
+		asc_scsi_q.q1.data_addr = 0;
+		asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+		ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
 
 		/*
 		 * Convert scatter-gather list into ASC_SG_HEAD list.
 		 */
 		slp = (struct scatterlist *) scp->request_buffer;
 		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-			sghead.sg_list[sgcnt].addr = (ulong) slp->address;
-			sghead.sg_list[sgcnt].bytes = slp->length;
+			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
 			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 		}
 	}
 
-	ASC_DBG_PRT_SCSI_Q(2, &scsiq);
+	ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q);
 	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
 	/*
-	 * Disable interrupts to issue the command and add the
-	 * command to the active queue if it is started.
+	 * Execute the command. If there is no error, add the command
+	 * to the active queue.
 	 */
-	save_flags(flags);
-	cli();
-
-	switch (ret = AscExeScsiQueue(asc_dvc_varp, &scsiq)) {
+	switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
 	case ASC_NOERROR:
-		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_STATS(scp->host, asc_noerror);
+		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
 		break;
 	case ASC_BUSY:
@@ -4083,24 +4493,24 @@
 		break;
 	case ASC_ERROR:
 		ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_error);
 		scp->result = HOST_BYTE(DID_ERROR);
-		scp->scsi_done(scp);
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		break;
 	default:
 		ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() unknown, err_code %x\n",
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_unknown);
 		scp->result = HOST_BYTE(DID_ERROR);
-		scp->scsi_done(scp);
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		break;
 	}
-	restore_flags(flags);
 
 	ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	return ret;
 }
 
@@ -4110,10 +4520,10 @@
 void
 asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 {
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	Scsi_Cmnd			*scp;
 	struct Scsi_Host	*shp;
-	Scsi_Cmnd			**scpp;
+	int					i;
 
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
@@ -4128,16 +4538,40 @@
 	ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
 	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
+	if (scp == NULL) {
+		ASC_PRINT("asc_isr_callback: scp is NULL\n");
+		return;
+	}
+
+	/*
+	 * If the request's host pointer is not valid, display a
+	 * message and return.
+	 */
 	shp = scp->host;
-	ASC_ASSERT(shp);
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i] == shp) {
+			break;
+		}
+	}
+	if (i == asc_board_count) {
+		ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
+			(unsigned) scp, (unsigned) shp);
+		return;
+	}
+
 	ASC_STATS(shp, callback);
 	ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
 
+	/*
+	 * If the request isn't found on the active queue, it may
+	 * have been removed to handle a reset or abort request.
+	 * Display a message and return.
+	 */
 	boardp = ASC_BOARDP(shp);
 	if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-		ASC_PRINT2(
-"asc_isr_callback: Board %d: scp %x not on active queue\n",
+		ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
 			boardp->id, (unsigned) scp);
+		return;
 	}
 
 	/*
@@ -4205,33 +4639,14 @@
 		break;
 	}
 
-	/*
-	 * Before calling 'scsi_done' for the current 'Scsi_Cmnd' and possibly
-	 * triggering more commands to be issued, try to start any pending
-	 * commands.
-	 */
-	if (boardp->pending.tidmask != 0) {
-	 	/*
-		 * If there are any pending commands for this board before trying
-	 	 * to execute them, disable interrupts to preserve request ordering.
-		 */
-		ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-		ASC_DBG1(1, "asc_isr_callback: asc_execute_queue() %x\n",
-			boardp->pending.tidmask);
-		asc_execute_queue(&boardp->pending);
-	}
-
 	/* 
-	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done function,
-	 * add the command to the end of the global done list. The done function
-	 * for the command will be called in advansys_interrupt().
+	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+	 * function, add the command to the end of the board's done queue.
+	 * The done function for the command will be called from
+	 * advansys_interrupt().
 	 */
-	for (scpp = &asc_scsi_done; *scpp;
-	     scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
-		;
-	}
-	*scpp = scp;
-	scp->host_scribble = NULL;
+	asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+
 	return;
 }
 
@@ -4243,10 +4658,7 @@
 STATIC int
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
-	struct asc_board		*boardp;
-	ASC_SCSI_REQ_Q			*scsireqq;
-	ASC_CAP_INFO			*cap_info;
-	ASC_SCSI_INQUIRY		*inquiry;
+	asc_board_t				*boardp;
 	int						found;
 	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
 	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
@@ -4257,26 +4669,15 @@
 
 	ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
 
-	/* The hosts's target id is set in init_tidmask during initialization. */
+	/* The host's target id is set in init_tidmask during initialization. */
 	ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target);
 
 	boardp = ASC_BOARDP(scp->host);
 
-	/*
-	 * XXX - Host drivers should not modify the timeout field.
-	 * But on the first command only add some extra time to
-	 * allow the driver to complete its initialization for the
-	 * device.
-	 */
-	scp->timeout += 2000;	/* Add 5 seconds to the request timeout. */
-
 	/* Set-up AscInitPollTarget() arguments. */
-	scsireqq = &boardp->scsireqq;
-	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-	cap_info = &boardp->cap_info;
-	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
-	inquiry = &boardp->inquiry;
-	memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+	memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+	memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO));
+	memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
 
 	/*
 	 * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4289,28 +4690,29 @@
 
 	ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
 	if (AscInitPollBegin(asc_dvc_varp)) {
-		ASC_PRINT1("asc_init_dev: Board %d: AscInitPollBegin() failed\n",
+		ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n",
 			boardp->id);
 		return ASC_FALSE;
 	}
 
-	scsireqq->sense_ptr = &scsireqq->sense[0];
-	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
-	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	scsireqq->r1.target_lun = 0;
-	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+	asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0];
+	asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN;
+	asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	asc_scsireqq.r1.target_lun = 0;
+	asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
 
 	found = ASC_FALSE;
 	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, cap_info)) {
+	switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
+		&asc_inquiry, &asc_cap_info)) {
 	case ASC_TRUE:
 		found = ASC_TRUE;
 #ifdef ADVANSYS_DEBUG
 		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
 		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-			cap_info->lba, cap_info->blk_size);
+			asc_cap_info.lba, asc_cap_info.blk_size);
 		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			inquiry->byte0.peri_dvc_type);
+			asc_inquiry.byte0.peri_dvc_type);
 		if (asc_dvc_varp->use_tagged_qng & tidmask) {
 			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
 				asc_dvc_varp->max_dvc_qng[scp->target]);
@@ -4334,12 +4736,12 @@
 		ASC_DBG(1, "asc_init_dev: no device found\n");
 		break;
 	case ASC_ERROR:
-		ASC_PRINT1("asc_init_dev: Board %d: AscInitPollTarget() ASC_ERROR\n",
+		ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n",
 				boardp->id);
 		break;
 	default:
 		ASC_PRINT2(
-"asc_init_dev: Board %d: AscInitPollTarget() unknown ret %d\n",
+"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n",
 				boardp->id, ret);
 		break;
 	}
@@ -4351,6 +4753,8 @@
 	ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
 	AscInitPollEnd(asc_dvc_varp);
 
+	ASC_DBG1(1, "asc_init_dev: found %d\n", found); 
+
 	return found;
 }
 
@@ -4753,36 +5157,42 @@
 void
 asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
 {
-	REQP	*reqpp;
 	int		tid;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
 		(unsigned) ascq, (unsigned) reqp, flag);
-	tid = REQPTID(reqp);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT(reqp != NULL);
 	ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+	tid = REQPTID(reqp);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
 	if (flag == ASC_FRONT) {
-		REQPNEXT(reqp) = ascq->queue[tid];
-		ascq->queue[tid] = reqp;
+		REQPNEXT(reqp) = ascq->q_first[tid];
+		ascq->q_first[tid] = reqp;
+		/* If the queue was empty, set the last pointer. */
+		if (ascq->q_last[tid] == NULL) {
+			ascq->q_last[tid] = reqp;
+		}
 	} else { /* ASC_BACK */
-		for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-			ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-			;
+		if (ascq->q_last[tid] != NULL) {
+			REQPNEXT(ascq->q_last[tid]) = reqp;
 		}
-		*reqpp = reqp;
+		ascq->q_last[tid] = reqp;
 		REQPNEXT(reqp) = NULL;
+		/* If the queue was empty, set the first pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_first[tid] = reqp;
+		}
 	}
 	/* The queue has at least one entry, set its bit. */
-	ascq->tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+	ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
-	ascq->cur_count[tid]++;
-	if (ascq->cur_count[tid] > ascq->max_count[tid]) {
-		ascq->max_count[tid] = ascq->cur_count[tid];
-		ASC_DBG2(1, "asc_enqueue: new max_count[%d] %d\n",
-			tid, ascq->max_count[tid]);
+	/* Maintain request queue statistics. */
+	ascq->q_cur_cnt[tid]++;
+	if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+		ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+		ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
+			tid, ascq->q_max_cnt[tid]);
 	}
 #endif /* ADVANSYS_STATS */
 	ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
@@ -4801,30 +5211,103 @@
 {
 	REQP	reqp;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
-	if ((reqp = ascq->queue[tid]) != NULL) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		ascq->queue[tid] = REQPNEXT(reqp);
-		/* If the queue is empty, clear its bit. */
-		if (ascq->queue[tid] == NULL) {
-			ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+	if ((reqp = ascq->q_first[tid]) != NULL) {
+		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
 		}
-	}
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
-	if (reqp != NULL) {
-		ascq->cur_count[tid]--;
-	}
-	ASC_ASSERT(ascq->cur_count[tid] >= 0);
+		/* Maintain request queue statistics. */
+		ascq->q_cur_cnt[tid]--;
+		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
+	}
 	ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
 	return reqp;
 }
 
 /*
+ * Return a pointer to a singly linked list of all the requests queued
+ * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
+ *
+ * If 'lastpp' is not NULL, '*lastpp' will be set to point to the 
+ * the last request returned in the singly linked list.
+ *
+ * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
+ * then all queued requests are concatenated into one list and
+ * returned.
+ *
+ * Note: If 'lastpp' is used to append a new list to the end of
+ * an old list, only change the old list last pointer if '*lastpp'
+ * (or the function return value) is not NULL, i.e. use a temporary
+ * variable for 'lastpp' and check its value after the function return
+ * before assigning it to the list last pointer.
+ */
+REQP
+asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+{
+	REQP	firstp, lastp;
+	int		i;
+
+	ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID));
+
+	/*
+	 * If 'tid' is not ASC_TID_ALL, return requests only for
+	 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+	 * requests for all tids.
+	 */
+	if (tid != ASC_TID_ALL) {
+		/* Return all requests for the specified 'tid'. */
+		if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
+			/* List is empty set first and last return pointers to NULL. */
+			firstp = lastp = NULL;
+		} else {
+			firstp = ascq->q_first[tid];
+			lastp = ascq->q_last[tid];
+			ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+#ifdef ADVANSYS_STATS
+			ascq->q_cur_cnt[tid] = 0;
+#endif /* ADVANSYS_STATS */
+		}
+	} else {
+		/* Return all requests for all tids. */
+		firstp = lastp = NULL;
+		for (i = 0; i <= ASC_MAX_TID; i++) {
+			if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+				if (firstp == NULL) {
+					firstp = ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				} else {
+					ASC_ASSERT(lastp != NULL);
+					REQPNEXT(lastp) = ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				}
+				ascq->q_first[i] = ascq->q_last[i] = NULL;
+				ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+#ifdef ADVANSYS_STATS
+				ascq->q_cur_cnt[i] = 0;
+#endif /* ADVANSYS_STATS */
+			}
+		}
+	}
+	if (lastpp) {
+		*lastpp = lastp;
+	}
+	ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+	return firstp;
+}
+
+/*
  * Remove the specified 'REQP' from the specified queue for
  * the specified target device. Clear the 'tidmask' bit for the
  * device if no more commands are left queued for it.
@@ -4837,34 +5320,61 @@
 int
 asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		*reqpp;
+	REQP		currp, prevp;
 	int			tid;
-	int			ret;
+	int			ret = ASC_FALSE;
 
+	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n",
+		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ret = ASC_FALSE;
+	ASC_ASSERT(reqp != NULL);
+
 	tid = REQPTID(reqp);
-	for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		if (*reqpp == reqp) {
-			ret = ASC_TRUE;
-			*reqpp = REQPNEXT(reqp);
-			REQPNEXT(reqp) = NULL;
-			/* If the queue is now empty, clear its bit. */
-			if (ascq->queue[tid] == NULL) {
-				ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+	/*
+	 * Handle the common case of 'reqp' being the first
+	 * entry on the queue.
+	 */
+	if (reqp == ascq->q_first[tid]) {
+		ret = ASC_TRUE;
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is now empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
+		}
+	} else if (ascq->q_first[tid] != NULL) {
+		ASC_ASSERT(ascq->q_last[tid] != NULL);
+		/*
+		 * Because the case of 'reqp' being the first entry has been
+		 * handled above and it is known the queue is not empty, if
+		 * 'reqp' is found on the queue it is guaranteed the queue will
+		 * not become empty and that 'q_first[tid]' will not be changed.
+		 *
+		 * Set 'prevp' to the first entry, 'currp' to the second entry,
+		 * and search for 'reqp'.
+		 */
+		for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+			 currp; prevp = currp, currp = REQPNEXT(currp)) {
+			if (currp == reqp) {
+				ret = ASC_TRUE;
+				REQPNEXT(prevp) = REQPNEXT(currp);
+				REQPNEXT(reqp) = NULL;
+				if (ascq->q_last[tid] == reqp) {
+					ascq->q_last[tid] = prevp;
+				}
+				break;
 			}
-			break; /* Note: *reqpp may now be NULL, don't iterate. */
 		}
 	}
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
+	/* Maintain request queue statistics. */
 	if (ret == ASC_TRUE) {
-		ascq->cur_count[tid]--;
+		ascq->q_cur_cnt[tid]--;
 	}
-	ASC_ASSERT(ascq->cur_count[tid] >= 0);
+	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
 	ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
 	return ret;
@@ -4877,16 +5387,21 @@
 int
 asc_isqueued(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		*reqpp;
+	REQP		treqp;
 	int			tid;
-	int			ret;
+	int			ret = ASC_FALSE;
 
+	ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n",
+		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ret = ASC_FALSE;
+	ASC_ASSERT(reqp != NULL);
+
 	tid = REQPTID(reqp);
-	for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		if (*reqpp == reqp) {
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+	for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
+		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+		if (treqp == reqp) {
 			ret = ASC_TRUE;
 			break;
 		}
@@ -4906,13 +5421,13 @@
 	REQP					reqp;
 	int						i;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	/*
 	 * Execute queued commands for devices attached to
 	 * the current board in round-robin fashion.
 	 */
-	scan_tidmask = ascq->tidmask;
+	scan_tidmask = ascq->q_tidmask;
 	do {
 		for (i = 0; i <= ASC_MAX_TID; i++) {
 			if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
@@ -4944,11 +5459,11 @@
 STATIC int
 asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-	int					i;
+	asc_board_t		*boardp;
+	int				leftlen;
+	int				totlen;
+	int				len;
+	int				i;
 
 	boardp = ASC_BOARDP(shp);
 	leftlen = cplen;
@@ -4989,14 +5504,14 @@
 STATIC int
 asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-	ASCEEP_CONFIG       *ep;
-	int					i;
-	int					isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	int				leftlen;
+	int				totlen;
+	int				len;
+	ASCEEP_CONFIG	*ep;
+	int				i;
+	int				isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
 
 	boardp = ASC_BOARDP(shp);
 	asc_dvc_varp = &boardp->asc_dvc_var;
@@ -5069,6 +5584,70 @@
 }
 
 /*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+{
+	int					leftlen;
+	int					totlen;
+	int					len;
+
+	leftlen = cplen;
+	totlen = len = 0;
+
+	len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+		shp->host_no);
+	ASC_PRT_NEXT();
+
+	len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
+		shp->max_channel);
+#else /* version >= v1.3.89 */
+" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
+		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
+#endif /* version >= v1.3.89 */
+	ASC_PRT_NEXT();
+	
+	len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+		shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
+		shp->cmd_per_lun);
+#else /* version >= v1.3.57 */
+" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
+#endif /* version >= v1.3.57 */
+	ASC_PRT_NEXT();
+
+	len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
+		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+#else /* version >= v1.3.57 */
+" unchecked_isa_dma %d, loaded_as_module %d\n",
+		shp->unchecked_isa_dma, shp->loaded_as_module);
+#endif /* version >= v1.3.57 */
+	ASC_PRT_NEXT();
+
+	len = asc_prt_line(cp, leftlen,
+" flags %x, reset_jiffies %x, jiffies %x\n",
+		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->reset_jiffies, jiffies);
+	ASC_PRT_NEXT();
+
+ 	return totlen;
+}
+
+/*
  * asc_prt_board_info()
  *
  * Print dynamic board configuration information.
@@ -5082,7 +5661,7 @@
 STATIC int
 asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	int					leftlen;
 	int					totlen;
 	int					len;
@@ -5106,7 +5685,7 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %u, lib_serial_no %u mcode_date %u\n",
+" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n",
 		c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
 	ASC_PRT_NEXT();
 
@@ -5115,7 +5694,7 @@
 		 c->mcode_version, v->err_code);
 	ASC_PRT_NEXT();
 
-	/* Current number of commands pending for the host. */
+	/* Current number of commands waiting for the host. */
 	len = asc_prt_line(cp, leftlen,
 " Total Command Pending:    %d\n", v->cur_total_qng);
 	ASC_PRT_NEXT();
@@ -5150,7 +5729,7 @@
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
-	/* Current number of commands pending for a device. */
+	/* Current number of commands waiting for a device. */
 	len = asc_prt_line(cp, leftlen,
 " Command Queue Pending:   ");
 	ASC_PRT_NEXT();
@@ -5495,7 +6074,7 @@
 }
 
 /*
- * Return the BIOS address of the adatper at the specified
+ * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  *
  * This function was formerly supplied by the library.
@@ -5565,7 +6144,7 @@
 	struct asc_stats	*s;
 	int					i;
 	asc_queue_t			*active;
-	asc_queue_t			*pending;
+	asc_queue_t			*waiting;
 
 	leftlen = cplen;
 	totlen = len = 0;
@@ -5581,8 +6160,8 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" check_interrupt %lu, interrupt %lu, callback %lu\n",
-		s->check_interrupt, s->interrupt, s->callback);
+" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n",
+		s->check_interrupt, s->interrupt, s->callback, s->done);
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
@@ -5598,13 +6177,13 @@
 	ASC_PRT_NEXT();
 
 	active = &ASC_BOARDP(shp)->active;
-	pending = &ASC_BOARDP(shp)->pending;
+	waiting = &ASC_BOARDP(shp)->waiting;
 	for (i = 0; i < ASC_MAX_TID + 1; i++) {
-		if (active->max_count[i] > 0 || pending->max_count[i] > 0) {
+		if (active->q_max_cnt[i] > 0 || waiting->q_max_cnt[i] > 0) {
 			len = asc_prt_line(cp, leftlen,
-"  target %d: active [cur %d, max %d], pending [cur %d, max %d]\n",
-				i, active->cur_count[i], active->max_count[i],
-				pending->cur_count[i], pending->max_count[i]);
+"  target %d: active [cur %d, max %d], waiting [cur %d, max %d]\n",
+				i, active->q_cur_cnt[i], active->q_max_cnt[i],
+				waiting->q_cur_cnt[i], waiting->q_max_cnt[i]);
 			ASC_PRT_NEXT();
 		}
 	}
@@ -6287,10 +6866,11 @@
 					sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET;
 				}
 				if (
-					   (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[0])
+					   (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index])
 					   || (sdtr_xmsg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])
 				  ) {
 					sdtr_accept = FALSE;
+					sdtr_xmsg.xfer_period = asc_dvc->sdtr_period_tbl[ asc_dvc->host_init_sdtr_index ] ;
 				}
 				if (sdtr_accept) {
 					sdtr_data = AscCalSDTRData(asc_dvc, sdtr_xmsg.xfer_period,
@@ -6344,7 +6924,7 @@
 			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
 			q_cntl |= QC_MSG_OUT;
 			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
 						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
 		}
 #endif
@@ -6418,8 +6998,8 @@
 				}
 #ifdef ADVANSYS_STATS
 				{
-					struct asc_board   *boardp;
-					int                 i;
+					asc_board_t		*boardp;
+					int				i;
 					for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
 						if (asc_host[i] == NULL) {
 							continue;
@@ -6768,156 +7348,156 @@
 	return (0);
 }
 
-uchar               _mcode_buf[] =
-{
-	0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 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, 0xC4, 0x0C, 0x08, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00,
-	0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC6, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
-	0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC6, 0x00, 0x92, 0x80,
-	0x20, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
-	0x4F, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
-	0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
-	0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x00, 0xA8, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
-	0xD2, 0x84, 0xD0, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE6, 0x01, 0xA8, 0x97,
-	0xD2, 0x81, 0x00, 0x33, 0x02, 0x00, 0xC2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1,
-	0x06, 0x01, 0x4F, 0x00, 0x86, 0x97, 0x07, 0xA6, 0x10, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
-	0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
-	0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x84, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x30, 0x01, 0x84, 0x81,
-	0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x40, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88,
-	0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x6A, 0x98, 0x4D, 0x04, 0xF0, 0x84, 0x05, 0xD8,
-	0x0D, 0x23, 0x6A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01,
-	0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00,
-	0x07, 0xA3, 0x7A, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
-	0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x94, 0x81, 0x06, 0xAB, 0x8E, 0x01, 0x94, 0x81, 0x4E, 0x00,
-	0x07, 0xA3, 0x9E, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x48, 0x01, 0x00, 0x05, 0x88, 0x81, 0x48, 0x97,
-	0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCA, 0x81, 0xFD, 0x23,
-	0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC0, 0x01, 0x80, 0x63,
-	0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, 0x6A, 0x98, 0xCD, 0x04,
-	0xD2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE0, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE6, 0x01, 0xD2, 0x84,
-	0x80, 0x23, 0xA0, 0x01, 0xD2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x02,
-	0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x86, 0x97, 0x08, 0x82, 0x08, 0x23,
-	0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x64, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, 0xF2, 0x97,
-	0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42,
-	0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x06, 0x98, 0xF8, 0x80, 0x80, 0x73,
-	0x80, 0x77, 0x06, 0xA6, 0x3C, 0x02, 0x00, 0x33, 0x31, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x03, 0xD8,
-	0xB4, 0x98, 0x3E, 0x96, 0x4E, 0x82, 0xCE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D,
-	0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02,
-	0x00, 0x33, 0x10, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x50, 0x82, 0x34, 0x96, 0x50, 0x82, 0x04, 0x23,
-	0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x28, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61,
-	0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01,
-	0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x66, 0x02,
-	0x06, 0xA6, 0x6A, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43,
-	0x00, 0xA0, 0x98, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01,
-	0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
-	0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00,
-	0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x80, 0x98, 0xB6, 0x2D, 0x01, 0xA6,
-	0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
-	0x0C, 0x04, 0x02, 0xA6, 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xEE, 0x82,
-	0x34, 0x96, 0xEE, 0x82, 0x84, 0x98, 0x80, 0x42, 0x80, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8,
-	0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x88, 0x98,
-	0x80, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x28, 0x04, 0x06, 0xA6,
-	0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x32, 0x83,
-	0x34, 0x96, 0x32, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC2, 0x88,
-	0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x72, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
-	0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x92, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38,
-	0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x8E, 0x03, 0x00, 0xA6, 0x8E, 0x03, 0x02, 0x84, 0x80, 0x42,
-	0x80, 0x98, 0x01, 0xA6, 0x9C, 0x03, 0x00, 0xA6, 0xB4, 0x03, 0x02, 0x84, 0xA8, 0x98, 0x80, 0x42,
-	0x01, 0xA6, 0x9C, 0x03, 0x07, 0xA6, 0xAA, 0x03, 0xCC, 0x83, 0x6A, 0x95, 0xA0, 0x83, 0x00, 0x33,
-	0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xB4, 0x03, 0x07, 0xA6, 0xC2, 0x03,
-	0xCC, 0x83, 0x6A, 0x95, 0xB8, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
-	0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x02, 0x84, 0x04, 0xF0, 0x80, 0x6B,
-	0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0x03, 0xA6, 0x00, 0x04, 0x07, 0xA6, 0xF8, 0x03, 0x06, 0xA6,
-	0xFC, 0x03, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xE6, 0x83, 0x34, 0x96, 0xE6, 0x83,
-	0x0C, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0xB6, 0x2D, 0x03, 0xA6,
-	0x28, 0x04, 0x07, 0xA6, 0x20, 0x04, 0x06, 0xA6, 0x24, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88,
-	0x6A, 0x95, 0x0C, 0x84, 0x34, 0x96, 0x0C, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
-	0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x46, 0x04,
-	0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x50, 0x04,
-	0x23, 0x01, 0x00, 0xA2, 0x72, 0x04, 0x0A, 0xA0, 0x62, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
-	0xC2, 0x88, 0x0B, 0xA0, 0x6E, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xC2, 0x88, 0x42, 0x23,
-	0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x28, 0x23,
-	0x22, 0xA3, 0x9A, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB0, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
-	0x06, 0x61, 0x00, 0xA0, 0x9A, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x06, 0x98, 0x00, 0xA2, 0xAC, 0x04,
-	0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF4, 0x81, 0x47, 0x23, 0xF8, 0x88,
-	0x04, 0x01, 0x0B, 0xDE, 0x06, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
-	0x14, 0x01, 0x00, 0xA0, 0x0E, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23,
-	0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE0, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88,
-	0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x06, 0x98, 0x14, 0x95,
-	0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x0E, 0x05, 0x00, 0x05, 0x76, 0x00,
-	0x06, 0x61, 0x00, 0xA2, 0x08, 0x05, 0xF6, 0x84, 0x48, 0x97, 0xCD, 0x04, 0x12, 0x85, 0x48, 0x04,
-	0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x22, 0x85, 0x02, 0x23,
-	0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x2E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23,
-	0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01,
-	0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00,
-	0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x4E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00,
-	0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xCC, 0x05, 0x03, 0x03,
-	0x02, 0xA0, 0x7C, 0x05, 0xC8, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xA2, 0x05,
-	0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x8E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23,
-	0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x64, 0x97, 0xF0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01,
-	0xF0, 0x84, 0x08, 0xA0, 0xA8, 0x05, 0xC8, 0x85, 0x03, 0xA0, 0xAE, 0x05, 0xC8, 0x85, 0x01, 0xA0,
-	0xBA, 0x05, 0x88, 0x00, 0x80, 0x63, 0xB8, 0x96, 0x6A, 0x85, 0x07, 0xA0, 0xC6, 0x05, 0x06, 0x23,
-	0x6A, 0x98, 0x48, 0x23, 0xF8, 0x88, 0xC8, 0x86, 0x80, 0x63, 0x6A, 0x85, 0x00, 0x63, 0x4A, 0x00,
-	0x06, 0x61, 0x00, 0xA2, 0x0A, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03,
-	0x80, 0x63, 0x06, 0xA6, 0xEC, 0x05, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x02, 0xD6,
-	0x46, 0x23, 0xF8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x04, 0x06, 0x00, 0x33,
-	0x38, 0x00, 0xC2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
-	0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x22, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
-	0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
-	0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6,
-	0x50, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x02, 0xA6, 0xFC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xC2, 0x88,
-	0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x64, 0x06,
-	0x07, 0xA6, 0xA4, 0x06, 0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63,
-	0x01, 0x00, 0x06, 0xA6, 0x80, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3A, 0x00, 0xC2, 0x88,
-	0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x72, 0x06, 0x06, 0xA6, 0x98, 0x06, 0x07, 0xA6,
-	0xA4, 0x06, 0x00, 0x33, 0x3B, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6,
-	0xA4, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0xB8, 0x06, 0x07, 0xA2,
-	0xFC, 0x06, 0x00, 0x33, 0x35, 0x00, 0xC2, 0x88, 0x07, 0xA6, 0xC2, 0x06, 0x00, 0x33, 0x2A, 0x00,
-	0xC2, 0x88, 0x03, 0x03, 0x03, 0xA2, 0xCE, 0x06, 0x07, 0x23, 0x80, 0x00, 0x08, 0x87, 0x80, 0x63,
-	0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xDE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43,
-	0x00, 0xA2, 0xEA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xD4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80,
-	0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33,
-	0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x5C, 0x06,
-	0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x30, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63,
-	0x06, 0xA6, 0x2E, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00,
-	0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x46, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0xBF, 0x23,
-	0x04, 0x61, 0x84, 0x01, 0xD2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01,
-	0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05,
-	0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00,
-	0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00,
-	0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00,
-	0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04,
-	0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01,
-	0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC6, 0x07,
-	0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
-	0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2,
-	0xE6, 0x07, 0x00, 0x05, 0xDC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05,
-	0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08,
-	0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02,
-	0x00, 0xA0, 0x16, 0x08, 0x18, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
-	0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2,
-	0x46, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x26, 0x08,
-	0x06, 0x98, 0x14, 0x95, 0x26, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5C, 0x88,
-	0x02, 0x01, 0x04, 0xD8, 0x48, 0x97, 0x06, 0x98, 0x14, 0x95, 0x4C, 0x88, 0x75, 0x00, 0x00, 0xA3,
-	0x66, 0x08, 0x00, 0x05, 0x50, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
-	0x78, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63,
-	0x38, 0x2B, 0x9E, 0x88, 0x38, 0x2B, 0x94, 0x88, 0x32, 0x09, 0x31, 0x05, 0x94, 0x98, 0x05, 0x05,
-	0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32,
-	0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
-	0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
-	0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
-	0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
-	0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
-	0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD2, 0x84,
-};
+uchar _mcode_buf[ ] = {
+  0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  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,  0x10,  0x0D,  0x09,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x21,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xDC,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
+  0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
+  0x18,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
+  0x4F,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
+  0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x00,  0xA3,  0xD6,  0x00,  0xA0,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0xD2,  0xC1,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA0,  0x97,  0xCE,  0x81,  0x00,  0x33,
+  0x02,  0x00,  0xBA,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
+  0x7E,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xDE,
+  0x00,  0x33,  0x05,  0x00,  0xBA,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
+  0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
+  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xBA,  0x88,  0x03,  0x07,  0x02,  0x01,
+  0x04,  0xCA,  0x0D,  0x23,  0x62,  0x98,  0x4D,  0x04,  0xEA,  0x84,  0x05,  0xD8,  0x0D,  0x23,  0x62,  0x98,
+  0xCD,  0x04,  0x15,  0x23,  0xF0,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
+  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xBA,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
+  0x00,  0x33,  0x0B,  0x00,  0xBA,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xBA,  0x88,
+  0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
+  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x40,  0x97,  0x02,  0x01,  0x05,  0xC6,
+  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
+  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
+  0x00,  0x33,  0x1B,  0x00,  0xBA,  0x88,  0x06,  0x23,  0x62,  0x98,  0xCD,  0x04,  0xCC,  0x84,  0x06,  0x01,
+  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xCC,  0x84,  0x80,  0x23,  0xA0,  0x01,
+  0xCC,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
+  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x7E,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
+  0x4F,  0x00,  0x5C,  0x97,  0x48,  0x04,  0x84,  0x80,  0xEA,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
+  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
+  0x11,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x06,  0xA6,  0x36,  0x02,
+  0x00,  0x33,  0x31,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x03,  0xD8,  0xAC,  0x98,  0x36,  0x96,  0x48,  0x82,
+  0xC6,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x72,  0x02,  0x07,  0xA6,
+  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,  0x68,  0x02,  0x00,  0x33,  0x10,  0x00,  0xBA,  0x88,
+  0x62,  0x95,  0x4A,  0x82,  0x2C,  0x96,  0x4A,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,
+  0x22,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,
+  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,
+  0x1C,  0x01,  0x02,  0xA6,  0xA4,  0x02,  0x07,  0xA6,  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x00,  0x33,
+  0x12,  0x00,  0xBA,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x92,  0x02,  0x4D,  0x04,
+  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,
+  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xE4,  0x82,  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,
+  0xDC,  0x02,  0x04,  0x01,  0x98,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xBA,  0x88,  0x08,  0x31,  0x0A,  0x35,
+  0x0C,  0x39,  0x0E,  0x3D,  0x78,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x0E,  0x03,  0x00,  0xA6,  0x0E,  0x03,
+  0x07,  0xA6,  0x06,  0x03,  0x06,  0xA6,  0x0A,  0x03,  0x03,  0xA6,  0x06,  0x04,  0x02,  0xA6,  0x72,  0x02,
+  0x00,  0x33,  0x33,  0x00,  0xBA,  0x88,  0x62,  0x95,  0xE8,  0x82,  0x2C,  0x96,  0xE8,  0x82,  0x7C,  0x98,
+  0x80,  0x42,  0x78,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,
+  0x4E,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x80,  0x98,  0x78,  0x98,  0x00,  0xA6,  0x10,  0x03,
+  0x07,  0xA6,  0x46,  0x03,  0x03,  0xA6,  0x22,  0x04,  0x06,  0xA6,  0x4A,  0x03,  0x01,  0xA6,  0x10,  0x03,
+  0x00,  0x33,  0x25,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x2C,  0x83,  0x2C,  0x96,  0x2C,  0x83,  0x04,  0x01,
+  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xBA,  0x88,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,
+  0x6C,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x28,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,
+  0x8C,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,
+  0x88,  0x03,  0x00,  0xA6,  0x88,  0x03,  0xFC,  0x83,  0x80,  0x42,  0x78,  0x98,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0xAE,  0x03,  0xFC,  0x83,  0xA0,  0x98,  0x80,  0x42,  0x01,  0xA6,  0x96,  0x03,  0x07,  0xA6,
+  0xA4,  0x03,  0xC6,  0x83,  0x62,  0x95,  0x9A,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xBA,  0x88,  0xA0,  0x98,
+  0x80,  0x42,  0x00,  0xA6,  0xAE,  0x03,  0x07,  0xA6,  0xBC,  0x03,  0xC6,  0x83,  0x62,  0x95,  0xB2,  0x83,
+  0x00,  0x33,  0x26,  0x00,  0xBA,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,
+  0x12,  0x23,  0xA1,  0x01,  0xFC,  0x83,  0x04,  0xF0,  0x80,  0x6B,  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,
+  0x03,  0xA6,  0xFA,  0x03,  0x07,  0xA6,  0xF2,  0x03,  0x06,  0xA6,  0xF6,  0x03,  0x00,  0x33,  0x17,  0x00,
+  0xBA,  0x88,  0x62,  0x95,  0xE0,  0x83,  0x2C,  0x96,  0xE0,  0x83,  0x06,  0x84,  0x04,  0xF0,  0x80,  0x6B,
+  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,  0xB6,  0x2D,  0x03,  0xA6,  0x22,  0x04,  0x07,  0xA6,  0x1A,  0x04,
+  0x06,  0xA6,  0x1E,  0x04,  0x00,  0x33,  0x30,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x06,  0x84,  0x2C,  0x96,
+  0x06,  0x84,  0x1D,  0x01,  0x06,  0xCC,  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,
+  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,  0x07,  0xA6,  0x40,  0x04,  0x00,  0x33,  0x18,  0x00,  0xBA,  0x88,
+  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,  0x07,  0xA4,  0x4A,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x6C,  0x04,
+  0x0A,  0xA0,  0x5C,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1D,  0x00,  0xBA,  0x88,  0x0B,  0xA0,  0x68,  0x04,
+  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,  0xBA,  0x88,  0x42,  0x23,  0xF0,  0x88,  0x00,  0x23,  0x22,  0xA3,
+  0xCC,  0x04,  0x08,  0x23,  0x22,  0xA3,  0x88,  0x04,  0x28,  0x23,  0x22,  0xA3,  0x94,  0x04,  0x02,  0x23,
+  0x22,  0xA3,  0xAA,  0x04,  0x42,  0x23,  0xF0,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0x94,  0x04,
+  0x45,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0x00,  0xA2,  0xA6,  0x04,  0xAC,  0x98,  0x00,  0x33,  0x00,  0x82,
+  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,  0x47,  0x23,  0xF0,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0xFE,  0x97,
+  0xAC,  0x98,  0x00,  0x33,  0x00,  0x81,  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,
+  0x43,  0x23,  0xF0,  0x88,  0x04,  0x23,  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,
+  0x03,  0xA3,  0xDA,  0x04,  0x00,  0x33,  0x27,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,
+  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xFE,  0x97,  0x0C,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,
+  0x4F,  0x00,  0x00,  0xA3,  0x08,  0x05,  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x05,
+  0xF0,  0x84,  0x40,  0x97,  0xCD,  0x04,  0x0A,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,
+  0x80,  0x23,  0x82,  0x01,  0x1A,  0x85,  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x26,  0x05,  0x1D,  0x01,  0x04,  0xD6,  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,
+  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,
+  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x46,  0x05,
+  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,
+  0x00,  0x63,  0x07,  0xA4,  0xC4,  0x05,  0x03,  0x03,  0x02,  0xA0,  0x74,  0x05,  0xC0,  0x85,  0x00,  0x33,
+  0x2D,  0x00,  0xBA,  0x88,  0x04,  0xA0,  0x9A,  0x05,  0x80,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x86,  0x05,  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x5C,  0x97,
+  0xEA,  0x84,  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0xEA,  0x84,  0x08,  0xA0,  0xA0,  0x05,  0xC0,  0x85,
+  0x03,  0xA0,  0xA6,  0x05,  0xC0,  0x85,  0x01,  0xA0,  0xB2,  0x05,  0x88,  0x00,  0x80,  0x63,  0xB0,  0x96,
+  0x62,  0x85,  0x07,  0xA0,  0xBE,  0x05,  0x06,  0x23,  0x62,  0x98,  0x48,  0x23,  0xF0,  0x88,  0xC0,  0x86,
+  0x80,  0x63,  0x62,  0x85,  0x00,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x06,  0x1D,  0x01,
+  0x18,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0xE4,  0x05,  0x00,  0x33,
+  0x37,  0x00,  0xBA,  0x88,  0x1D,  0x01,  0x02,  0xD6,  0x46,  0x23,  0xF0,  0x88,  0x63,  0x60,  0x83,  0x03,
+  0x80,  0x63,  0x06,  0xA6,  0xFC,  0x05,  0x00,  0x33,  0x38,  0x00,  0xBA,  0x88,  0xEF,  0x04,  0x6F,  0x00,
+  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1A,  0x06,
+  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,  0x04,  0xCC,  0x00,  0x33,
+  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,  0x80,  0x67,  0x08,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x06,  0xA6,  0x48,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x02,  0xA6,
+  0xF4,  0x06,  0x00,  0x33,  0x39,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x01,  0xA0,  0x0E,  0x07,  0xC6,  0x95,
+  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x5C,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x00,  0x01,  0xA0,
+  0x0E,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,  0x01,  0x00,  0x06,  0xA6,  0x78,  0x06,  0x07,  0xA6,
+  0x9C,  0x06,  0x00,  0x33,  0x3A,  0x00,  0xBA,  0x88,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,
+  0x6A,  0x06,  0x06,  0xA6,  0x90,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x33,  0x3B,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x40,  0x0E,  0x80,  0x63,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x63,  0x03,  0x03,  0x80,  0x63,
+  0x88,  0x00,  0x01,  0xA2,  0xB0,  0x06,  0x07,  0xA2,  0xF4,  0x06,  0x00,  0x33,  0x35,  0x00,  0xBA,  0x88,
+  0x07,  0xA6,  0xBA,  0x06,  0x00,  0x33,  0x2A,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xA2,  0xC6,  0x06,
+  0x07,  0x23,  0x80,  0x00,  0x00,  0x87,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,  0xD6,  0x06,
+  0x00,  0x33,  0x29,  0x00,  0xBA,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xE2,  0x06,  0xC0,  0x0E,  0x80,  0x63,
+  0xCC,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,  0x08,  0xDA,
+  0x80,  0x63,  0x00,  0x63,  0x80,  0x67,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,  0x81,  0x62,  0x00,  0x63,
+  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x54,  0x06,  0x00,  0x33,  0x2C,  0x00,  0xBA,  0x88,  0x0C,  0xA2,
+  0x28,  0x07,  0xC6,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x26,  0x07,  0x07,  0xA6,  0x9C,  0x06,
+  0x00,  0x33,  0x3D,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,
+  0x3E,  0x07,  0x07,  0xA6,  0x9C,  0x06,  0xBF,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0x00,  0x63,
+  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,
+  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,
+  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,
+  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,
+  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,
+  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,
+  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,
+  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xBE,  0x07,  0x00,  0x33,  0x07,  0x00,  0xBA,  0x88,  0x80,  0x05,
+  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,
+  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xDE,  0x07,  0x00,  0x05,  0xD4,  0x87,  0x00,  0x01,
+  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,
+  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,
+  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,  0x0E,  0x08,  0x10,  0x88,  0x00,  0x43,
+  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,
+  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x3E,  0x08,  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,
+  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x1E,  0x08,  0xFE,  0x97,  0x0C,  0x95,  0x1E,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x54,  0x88,  0x02,  0x01,  0x04,  0xD8,  0x40,  0x97,  0xFE,  0x97,
+  0x0C,  0x95,  0x44,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x5E,  0x08,  0x00,  0x05,  0x48,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x70,  0x08,  0x00,  0x33,  0x3E,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,  0x96,  0x88,  0x38,  0x2B,  0x8C,  0x88,
+  0x32,  0x09,  0x31,  0x05,  0x8C,  0x98,  0x05,  0x05,  0xB2,  0x09,  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,
+  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,
+  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,
+  0x00,  0xA0,  0xAC,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,
+  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,  0xF0,  0x88,  0x66,  0x20,  0xC0,  0x20,
+  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,  0xDA,  0x88,  0x80,  0x73,  0x80,  0x77,
+  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,  0x41,  0x23,  0xF0,  0x88,  0x11,  0x23,
+  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xCC,  0x84,
+} ;
+
+ushort _mcode_size = sizeof(_mcode_buf);
+ulong  _mcode_chksum = 0x012BA2FAUL ;
 
-ushort              _mcode_size = sizeof (_mcode_buf);
-ulong               _mcode_chksum = 0x012CD3FFUL;
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 uchar               _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
 {
@@ -6978,7 +7558,9 @@
 		return (ERR);
 	}
 	scsiq->q1.q_no = 0;
-	scsiq->q1.extra_bytes = 0;
+	if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+		scsiq->q1.extra_bytes = 0;
+	}
 	sta = 0;
 	target_ix = scsiq->q2.target_ix;
 	tid_no = ASC_TIX_TO_TID(target_ix);
@@ -6988,7 +7570,7 @@
 			((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) {
 			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
 			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
 						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
 			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
 		}
@@ -7082,7 +7664,7 @@
 					addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
 					  sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
 					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if (extra_bytes != 0) {
+					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
 						scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
 						scsiq->q1.extra_bytes = extra_bytes;
 						sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= (ulong) extra_bytes;
@@ -7122,7 +7704,7 @@
 				  ) {
 					addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
 					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if (extra_bytes != 0) {
+					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
 						if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
 							scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
 							scsiq->q1.data_cnt -= (ulong) extra_bytes;
@@ -7307,7 +7889,7 @@
 		return (cur_free_qs);
 	}
 	if (n_qs > 1) {
-		if (n_qs > asc_dvc->last_q_shortage) {
+		if ((n_qs > asc_dvc->last_q_shortage) && ( n_qs <= ( asc_dvc->max_total_qng - ASC_MIN_FREE_Q ))) {
 			asc_dvc->last_q_shortage = n_qs;
 		}
 	}
@@ -7332,7 +7914,7 @@
 		((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
 		tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
 		sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-		syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1);
+		syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
 		syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
 		AscMsgOutSDTR(asc_dvc,
 					  asc_dvc->sdtr_period_tbl[syn_period_ix],
@@ -8686,8 +9268,7 @@
 	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
 	asc_dvc->redo_scam = 0;
 	asc_dvc->res2 = 0;
-	asc_dvc->res4 = 0;
-	asc_dvc->res6 = 0;
+	asc_dvc->host_init_sdtr_index = 0;
 	asc_dvc->res7 = 0;
 	asc_dvc->res8 = 0;
 	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
@@ -8746,7 +9327,6 @@
 		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
 		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
 		asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-		asc_dvc->cfg->sdtr_period_offset[i] = (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4));
 	}
 	return (warn_code);
 }
@@ -8855,12 +9435,20 @@
 	}
 	eep_config->chip_scsi_id &= ASC_MAX_TID;
 	asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+	if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA ) == ASC_IS_PCI_ULTRA ) &&
+	    !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+		asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+	}
+
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 #if CC_TMP_USE_EEP_SDTR
 		asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i];
 #endif
 		asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
 		asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+		asc_dvc->cfg->sdtr_period_offset[i] =
+			(uchar) (ASC_DEF_SDTR_OFFSET |
+					 (asc_dvc->host_init_sdtr_index << 4));
 	}
 	eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
 #if CC_CHK_FIX_EEP_CONTENT
@@ -8880,6 +9468,7 @@
 	PortAddr            iop_base;
 	ushort              warn_code;
 	ushort              cfg_msw;
+	int					i;
 	iop_base = asc_dvc->iop_base;
 	warn_code = 0;
 	cfg_msw = AscGetChipCfgMsw(iop_base);
@@ -8889,12 +9478,19 @@
 		AscSetChipCfgMsw(iop_base, cfg_msw);
 	}
 	if (!AscTestExternalLram(asc_dvc)) {
-		if (asc_dvc->bus_type & ASC_IS_PCI) {
+		if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
+			asc_dvc->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG ;
+			for( i = 0 ; i <= ASC_MAX_TID ; i++ ) {
+				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG ;
+			}
+		} else {
 			cfg_msw |= 0x0800;
 			AscSetChipCfgMsw(iop_base, cfg_msw);
 			asc_dvc->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+			for (i = 0 ; i <= ASC_MAX_TID ; i++) {
+				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_INRAM_TAG_QNG;
+			}
 		}
-	} else {
 	}
 	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
 		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
@@ -8959,6 +9555,7 @@
 	ASC_ISR_CALLBACK    asc_isr_callback;
 	uchar               cp_sen_len;
 	uchar               i;
+	ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
 	if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
 		scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr;
 		scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
@@ -8981,6 +9578,7 @@
 			(*asc_isr_callback) (asc_dvc, scsi_done_q);
 		}
 	}
+	ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
 	return;
 }
 
@@ -9316,6 +9914,7 @@
 		asc_dvc->init_sdtr &= ~tid_bits;
 		tmp_disable_init_sdtr = TRUE;
 	}
+	ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n");
 	if (
 		   PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq,
 						   sizeof (ASC_SCSI_INQUIRY)) == 1
@@ -9353,19 +9952,8 @@
 					if (inq->byte7.CmdQue) {
 						asc_dvc->cfg->can_tagged_qng |= tid_bits;
 						if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
-#if CC_FIX_QUANTUM_XP34301_1071
-							if (
-								   (inq->add_len >= 32)
-								   && (AscCompareString(inq->vendor_id, (uchar *) "QUANTUM XP34301", 15) == 0)
-								   && (AscCompareString(inq->product_rev_level, (uchar *) "1071", 4) == 0)
-							  ) {
-							} else {
-#endif
 								asc_dvc->use_tagged_qng |= tid_bits;
 								asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no];
-#if CC_FIX_QUANTUM_XP34301_1071
-							}
-#endif
 						}
 					}
 					if (!inq->byte7.Sync) {
@@ -9404,12 +9992,12 @@
 				}
 			}
 			sta = 1;
-#if CC_INIT_TARGET_TEST_UNIT_READY
+			ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n");
 			sta = InitTestUnitReady(asc_dvc, scsiq);
-#endif
-#if CC_INIT_TARGET_READ_CAPACITY
 			if (sta == 1) {
 				if ((cap_info != 0L) && support_read_cap) {
+					ASC_DBG(1,
+						"AscInitPollTarget: before PollScsiReadCapacity\n");
 					if (PollScsiReadCapacity(asc_dvc, scsiq,
 											 cap_info) != 1) {
 						cap_info->lba = 0L;
@@ -9418,12 +10006,11 @@
 					}
 				}
 			}
-#endif
 		} else {
 			asc_dvc->start_motor &= ~tid_bits;
 		}
-	} else {
 	}
+	ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found);
 	return (dvc_found);
 }
 
@@ -9435,13 +10022,14 @@
 )
 {
 	int                 status;
-	int                 retry;
-	retry = 0;
+	int                 retry = 0;
+
+	ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
 	do {
-		if (
-			   (status = AscExeScsiQueue(asc_dvc,
-										 (ASC_SCSI_Q dosfar *) scsiq)) == 1
-		  ) {
+		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
+		if ((status = AscExeScsiQueue(asc_dvc,
+				(ASC_SCSI_Q dosfar *) scsiq)) == 1) {
+			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
 			if ((status = AscPollQDone(asc_dvc, scsiq,
 									   timeout_sec)) != 1) {
 				if (status == 0x80) {
@@ -9461,9 +10049,13 @@
 				scsiq->r3.scsi_msg = 0;
 				AscAbortSRB(asc_dvc, (ulong) scsiq);
 			}
+			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
 			return (scsiq->r3.done_stat);
 		}
-	} while ((status == 0) || (status == 0x80));
+		DvcSleepMilliSecond(5);
+	} while (((status == 0) || (status == 0x80)) &&
+			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
+	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
 
@@ -9481,7 +10073,6 @@
 	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4));
 }
 
-#if CC_INIT_TARGET_START_UNIT
 int
 PollScsiStartUnit(
 					 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9493,9 +10084,7 @@
 	}
 	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40));
 }
-#endif
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 PollScsiReadCapacity(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9522,7 +10111,6 @@
 	}
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
-#endif
 
 ulong dosfar       *
 swapfarbuf4(
@@ -9542,7 +10130,6 @@
 	return ((ulong dosfar *) buf);
 }
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 PollScsiTestUnitReady(
 						 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9603,7 +10190,6 @@
 	}
 	return (0);
 }
-#endif
 
 int
 AscPollQDone(
@@ -9866,7 +10452,6 @@
 	return (0);
 }
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 AscScsiReadCapacity(
 					   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9890,9 +10475,7 @@
 	scsiq->r2.cdb_len = 10;
 	return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 AscScsiTestUnitReady(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9913,9 +10496,7 @@
 	scsiq->r2.cdb_len = 6;
 	return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_START_UNIT
 int
 AscScsiStartStopUnit(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9936,4 +10517,3 @@
 	scsiq->r2.cdb_len = 6;
 	return (0);
 }
-#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- lx2.0/v2.0.21/linux/drivers/scsi/advansys.h	Sat Aug 17 21:19:27 1996
+++ linux/drivers/scsi/advansys.h	Fri Sep 27 07:52:57 1996
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1.11 1996/08/12 17:20:44 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.12 1996/09/23 18:12:02 bobf Exp bobf $ */
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
  *
@@ -85,10 +85,12 @@
 	1,						/* unsigned unchecked_isa_dma:1 */ \
 	/* \
 	 * All adapters controlled by this driver are capable of large \
-	 * scatter-gather lists. This apparently obviates any performance
-	 * gain provided by setting 'use_clustering'. \
+	 * scatter-gather lists. According to the mid-level SCSI documentation \
+	 * this obviates any performance gain provided by setting \
+	 * 'use_clustering'. But empirically while CPU utilization is increased \
+	 * by enabling clustering, I/O throughput increases as well. \
 	 */ \
-	DISABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
+	ENABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
 }
 #else /* version >= v1.3.0 */
 #define ADVANSYS { \
@@ -126,10 +128,12 @@
 	1,						/* unsigned unchecked_isa_dma:1 */ \
 	/* \
 	 * All adapters controlled by this driver are capable of large \
-	 * scatter-gather lists. This apparently obviates any performance
-	 * gain provided by setting 'use_clustering'. \
+	 * scatter-gather lists. According to the mid-level SCSI documentation \
+	 * this obviates any performance gain provided by setting \
+	 * 'use_clustering'. But empirically while CPU utilization is increased \
+	 * by enabling clustering, I/O throughput increases as well. \
 	 */ \
-	DISABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
+	ENABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
 }
 #endif /* version >= v1.3.0 */
 #endif /* _ADVANSYS_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- lx2.0/v2.0.21/linux/drivers/scsi/aha152x.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/scsi/aha152x.c	Sat Sep 28 11:37:41 1996
@@ -523,19 +523,19 @@
 
 #if !defined(SKIP_BIOSTEST)
 /* possible locations for the Adaptec BIOS */
-static void *addresses[] =
+static unsigned int addresses[] =
 {
-  (void *) 0xdc000,   /* default first */
-  (void *) 0xc8000,
-  (void *) 0xcc000,
-  (void *) 0xd0000,
-  (void *) 0xd4000,
-  (void *) 0xd8000,
-  (void *) 0xe0000,
-  (void *) 0xeb800,   /* VTech Platinum SMP */
-  (void *) 0xf0000,
+  0xdc000,   /* default first */
+  0xc8000,
+  0xcc000,
+  0xd0000,
+  0xd4000,
+  0xd8000,
+  0xe0000,
+  0xeb800,   /* VTech Platinum SMP */
+  0xf0000,
 };
-#define ADDRESS_COUNT (sizeof(addresses) / sizeof(void *))
+#define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int))
 
 /* signatures for various AIC-6[23]60 based controllers.
    The point in detecting signatures is to avoid useless and maybe
@@ -545,7 +545,7 @@
    needed anyway.  May be an information whether or not the BIOS supports
    extended translation could be also useful here. */
 static struct signature {
-  char *signature;
+  unsigned char *signature;
   int  sig_offset;
   int  sig_length;
 } signatures[] =
@@ -895,9 +895,8 @@
     ok=0;
     for(i=0; i < ADDRESS_COUNT && !ok; i++)
       for(j=0; (j < SIGNATURE_COUNT) && !ok; j++)
-        ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
-                   (void *) signatures[j].signature,
-                   (int) signatures[j].sig_length);
+      	ok = check_signature(addresses[i]+signatures[j].sig_offset,
+      		signatures[j].signature, signatures[j].sig_length);
 
     if(!ok && setup_count==0)
       return 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- lx2.0/v2.0.21/linux/drivers/scsi/aha1542.c	Mon Aug  5 10:13:52 1996
+++ linux/drivers/scsi/aha1542.c	Thu Sep 26 09:30:57 1996
@@ -35,6 +35,14 @@
 
 #include "aha1542.h"
 
+#define SCSI_PA(address) virt_to_bus(address)
+
+#define BAD_DMA(msg, address, length) \
+  { \
+    printk(KERN_CRIT "%s address %p length %d\n", msg, address, length); \
+    panic("Buffer at physical address > 16Mb used for aha1542"); \
+  }
+
 #include<linux/stat.h>
 
 struct proc_dir_entry proc_scsi_aha1542 = {
@@ -427,7 +435,7 @@
 	return;
       };
 
-      mbo = (scsi2int(mb[mbi].ccbptr) - ((unsigned int) &ccb[0])) / sizeof(struct ccb);
+      mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
       mbistatus = mb[mbi].status;
       mb[mbi].status = 0;
       HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
@@ -587,7 +595,7 @@
     printk("Sending command (%d %x)...",mbo, done);
 #endif
 
-    any2scsi(mb[mbo].ccbptr, &ccb[mbo]); /* This gets trashed for some reason*/
+    any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
 
     memset(&ccb[mbo], 0, sizeof(struct ccb));
 
@@ -627,12 +635,13 @@
 	  for(i=0;i<18;i++) printk("%02x ", ptr[i]);
 	  panic("Foooooooood fight!");
 	};
-	any2scsi(cptr[i].dataptr, sgpnt[i].address);
-	if(((unsigned  int) sgpnt[i].address) & 0xff000000) goto baddma;
+	any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
+	if(SCSI_PA(sgpnt[i].address+sgpnt[i].length) > ISA_DMA_THRESHOLD)
+	  BAD_DMA("sgpnt", sgpnt[i].address, sgpnt[i].length);
 	any2scsi(cptr[i].datalen, sgpnt[i].length);
       };
       any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
-      any2scsi(ccb[mbo].dataptr, cptr);
+      any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
 #ifdef DEBUG
       printk("cptr %x: ",cptr);
       ptr = (unsigned char *) cptr;
@@ -642,8 +651,9 @@
       ccb[mbo].op = 0;	      /* SCSI Initiator Command */
       SCpnt->host_scribble = NULL;
       any2scsi(ccb[mbo].datalen, bufflen);
-      if(((unsigned int) buff & 0xff000000)) goto baddma;
-      any2scsi(ccb[mbo].dataptr, buff);
+      if(buff && SCSI_PA(buff+bufflen) > ISA_DMA_THRESHOLD)
+        BAD_DMA("buff", buff, bufflen);
+      any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
     };
     ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
     ccb[mbo].rsalen = 16;
@@ -669,8 +679,6 @@
       printk("aha1542_queuecommand: done can't be NULL\n");
     
     return 0;
- baddma:
-    panic("Buffer at address  > 16Mb used for 1542B");
 }
 
 static void internal_done(Scsi_Cmnd * SCpnt)
@@ -704,10 +712,10 @@
 
     for(i=0; i<AHA1542_MAILBOXES; i++){
       mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0;
-      any2scsi(mb[i].ccbptr, &ccb[i]);
+      any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
     };
     aha1542_intr_reset(bse);     /* reset interrupts, so they don't block */	
-    any2scsi((cmd+2), mb);
+    any2scsi((cmd+2), SCSI_PA(mb));
     aha1542_out(bse, cmd, 5);
     WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
     while (0) {
@@ -942,7 +950,7 @@
 
 		    /* For now we do this - until kmalloc is more intelligent
 		       we are resigned to stupid hacks like this */
-		    if ((unsigned int) shpnt > 0xffffff) {
+		    if (SCSI_PA(shpnt+1) > ISA_DMA_THRESHOLD) {
 		      printk("Invalid address for shpnt with 1542.\n");
 		      goto unregister;
 		    }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- lx2.0/v2.0.21/linux/drivers/scsi/in2000.c	Thu May  9 16:40:24 1996
+++ linux/drivers/scsi/in2000.c	Wed Sep 25 08:35:23 1996
@@ -128,8 +128,8 @@
 #endif
 
 
-#define IN2000_VERSION    "1.28"
-#define IN2000_DATE       "07/May/1996"
+#define IN2000_VERSION    "1.29"
+#define IN2000_DATE       "24/Sep/1996"
 
 #define PROC_INTERFACE     /* add code for /proc/scsi/in2000/xxx interface */
 #define SYNC_DEBUG         /* extra info on sync negotiation printed */
@@ -1924,6 +1924,11 @@
    };
 
 
+/* As of the 2.1.x kernel series, memory-mapped hardware such
+ * as the IN2000 EPROM and dip switch must be accessed through
+ * special macros declared in 'asm/io.h'. We use readb() and
+ * readl() when reading from the card's BIOS area in in2000_detect().
+ */
 const unsigned int *bios_tab[] = {
    (unsigned int *)0xc8000,
    (unsigned int *)0xd0000,
@@ -1983,13 +1988,13 @@
          printk("Forcing IN2000 detection at IOport 0x%x ",base);
          bios = 2;
          }
-      else if (*(bios_tab[bios]+0x04) == 0x41564f4e ||
-          *(bios_tab[bios]+0x0c) == 0x61776c41) {
+      else if (readl(bios_tab[bios]+0x04) == 0x41564f4e ||
+               readl(bios_tab[bios]+0x0c) == 0x61776c41) {
          printk("Found IN2000 BIOS at 0x%x ",(unsigned int)bios_tab[bios]);
 
 /* Read the switch image that's mapped into EPROM space */
 
-         switches = ~((*(bios_tab[bios]+0x08) & 0xff));
+         switches = ~((readb(bios_tab[bios]+0x08) & 0xff));
 
 /* Find out where the IO space is */
 
@@ -2082,7 +2087,7 @@
 
 /* Older BIOS's had a 'sync on/off' switch - use its setting */
 
-      if (*(bios_tab[bios]+0x04) == 0x41564f4e && (switches & SW_SYNC_DOS5))
+      if (readl(bios_tab[bios]+0x04) == 0x41564f4e && (switches & SW_SYNC_DOS5))
          hostdata->sync_off = 0x00;    /* sync defaults to on */
       else
          hostdata->sync_off = 0xff;    /* sync defaults to off */
@@ -2188,31 +2193,21 @@
       iinfo[0] = 255;
       iinfo[1] = 63;
       iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+
+/* This next little bit of code was intended to prevent the number of
+ * tracks from exceeding 1023. As Andries Brouwer (aeb@cwi.nl) pointed
+ * out in his "Large Disk HOWTO" (June 1996), this kind of DOS
+ * compatibility is pointless. And wasteful on disks larger than 8 gigs.
+ */
+
+#if 0
       if (iinfo[2] > 1023)
          iinfo[2] = 1023;
+#endif
+
       }
     return 0;
 }
-
-
-#ifdef PROC_INTERFACE
-
-/* Certain older compilers (such as a.out 2.5.8) choke and give a
- * "Too many reloads" error when there are a lot of calls to 'strcat()'
- * in one function. Modern kernels define 'strcat()' as an inline
- * function - I _guess_ this is related to the problem. Regardless,
- * we can make everyone happy by doing some macro fudging to force
- * gcc to do calls instead of inline expansion.
- */
-
-char * in2000_strcat(char * dest, const char * src)
-{
-   return strcat(dest,src);
-}
-
-#define strcat(d,s) (in2000_strcat((d),(s)))
-
-#endif
 
 
 int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- lx2.0/v2.0.21/linux/drivers/scsi/in2000.h	Thu May  9 16:40:24 1996
+++ linux/drivers/scsi/in2000.h	Wed Sep 25 08:35:23 1996
@@ -2,7 +2,7 @@
  *    in2000.h -  Linux device driver definitions for the
  *                Always IN2000 ISA SCSI card.
  *
- *    IMPORTANT: This file is for version 1.28 - 07/May/1996
+ *    IMPORTANT: This file is for version 1.29 - 24/Sep/1996
  *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/in2000.readme linux/drivers/scsi/in2000.readme
--- lx2.0/v2.0.21/linux/drivers/scsi/in2000.readme	Thu Jun  6 13:00:20 1996
+++ linux/drivers/scsi/in2000.readme	Thu Jan  1 02:00:00 1970
@@ -1,155 +0,0 @@
-
-UPDATE NEWS: version 1.28 - 07 May 96
-
-   Tightened up the "interrupts enabled/disabled" discipline
-   in 'in2000_queuecommand()' and maybe 1 or 2 other places.
-   I _think_ it may have been a little too lax, causing an
-   occasional crash during full moon. A fully functional
-   /proc interface is now in place - if you want to play
-   with it, start by doing 'cat /proc/scsi/in2000/0'. You
-   can also use it to change a few run-time parameters on
-   the fly, but it's mostly for debugging. The curious
-   should take a good look at 'in2000_proc_info()' in the
-   in2000.c file to get an understanding of what it's all
-   about; I figure that people who are really into it will
-   want to add features suited to their own needs...
-   Also, sync is now DISABLED by default.
-
-UPDATE NEWS: version 1.27 - 10 Apr 96
-
-   Fixed a well-hidden bug in the adaptive-disconnect code
-   that would show up every now and then during extreme
-   heavy loads involving 2 or more simultaneously active
-   devices. Thanks to Joe Mack for keeping my nose to the
-   grindstone on this one.
-
-UPDATE NEWS: version 1.26 - 07 Mar 96
-
-   1.25 had a nasty bug that bit people with swap partitions
-   and tape drives. Also, in my attempt to guess my way
-   through Intel assembly language, I made an error in the
-   inline code for IO writes. Made a few other changes and
-   repairs - this version (fingers crossed) should work well.
-
-UPDATE NEWS: version 1.25 - 05 Mar 96
-
-   Kernel 1.3.70 interrupt mods added; old kernels still OK.
-   Big help from Bill Earnest and David Willmore on speed
-   testing and optimizing: I think there's a real improvement
-   in this area.
-   New! User-friendly command-line interface for LILO and
-   module loading - the old method is gone, so you'll need
-   to read the comments for 'setup_strings' near the top
-   of in2000.c. For people with CDROM's or other devices
-   that have a tough time with sync negotiation, you can
-   now selectively disable sync on individual devices -
-   search for the 'nosync' keyword in the command-line
-   comments. Some of you disable the BIOS on the card, which
-   caused the auto-detect function to fail; there is now a
-   command-line option to force detection of a ROM-less card.
-
-UPDATE NEWS: version 1.24a - 24 Feb 96
-
-   There was a bug in the synchronous transfer code. Only
-   a few people downloaded before I caught it - could have
-   been worse.
-
-UPDATE NEWS: version 1.24 - 23 Feb 96
-
-   Lots of good changes. Advice from Bill Earnest resulted
-   in much better detection of cards, more efficient usage
-   of the fifo, and (hopefully) faster data transfers. The
-   jury is still out on speed - I hope it's improved some.
-   One nifty new feature is a cool way of doing disconnect/
-   reselect. The driver defaults to what I'm calling
-   'adaptive disconnect' - meaning that each command is
-   evaluated individually as to whether or not it should be
-   run with the option to disconnect/reselect (if the device
-   chooses), or as a "SCSI-bus-hog". When several devices
-   are operating simultaneously, disconnects are usually an
-   advantage. In a single device system, or if only 1 device
-   is being accessed, transfers usually go faster if disconnects
-   are not allowed.
-
-
-
-The default arguments (you get these when you don't give an 'in2000'
-command-line argument, or you give a blank argument) will cause
-the driver to do adaptive disconnect, synchronous transfers, and a
-minimum of debug messages. If you want to fool with the options,
-search for 'setup_strings' near the top of the in2000.c file and
-check the 'hostdata->args' section in in2000.h - but be warned! Not
-everything is working yet (some things will never work, probably).
-I believe that disabling disconnects (DIS_NEVER) will allow you
-to choose a LEVEL2 value higher than 'L2_BASIC', but I haven't
-spent a lot of time testing this. You might try 'ENABLE_CLUSTERING'
-to see what happens: my tests showed little difference either way.
-There's also a define called 'DEFAULT_SX_PER'; this sets the data
-transfer speed for the asynchronous mode. I've put it at 500 ns
-despite the fact that the card could handle settings of 376 or
-252, because I'm not really sure if certain devices or maybe bad
-cables might have trouble at higher speeds. I couldn't find any
-info in my various SCSI references that talk about this in language
-I could understand, so decided to compromise with 500. This is still
-faster than the old driver was set at (I think). Can someone explain
-the significance of the bus transfer speed setting? Do devices on
-the bus ever care what it is? Is cable quality a factor here?
-Regardless, you can choose your own default through the command-
-line with the 'period' keyword.
-
-
-------------------------------------------------
-***********  DIP switch settings  **************
-------------------------------------------------
-
-   sw1-1 sw1-2    BIOS address (hex)
-   -----------------------------------------
-    off   off     C8000 - CBFF0
-    on    off     D8000 - DBFF0
-    off   on      D0000 - D3FF0
-    on    on      BIOS disabled
-
-   sw1-3 sw1-4    IO port address (hex)
-   ------------------------------------
-    off   off     220 - 22F
-    on    off     200 - 20F
-    off   on      110 - 11F
-    on    on      100 - 10F
-
-   sw1-5 sw1-6 sw1-7    Interrupt
-   ------------------------------
-    off   off   off     15
-    off   on    off     14
-    off   off   on      11
-    off   on    on      10
-    on    -     -       disabled
-
-   sw1-8 function depends on BIOS version. In earlier versions this
-   controlled synchronous data transfer support for MSDOS:
-      off = disabled
-      on  = enabled
-   In later ROMs (starting with 01.3 in April 1994) sw1-8 controls
-   the "greater than 2 disk drive" feature that first appeared in
-   MSDOS 5.0 (ignored by linux):
-      off = 2 drives maximum
-      on  = 7 drives maximum
-
-   sw1-9    Floppy controller
-   --------------------------
-    off     disabled
-    on      enabled
-
-------------------------------------------------
-
-   I should mention that Drew Eckhardt's 'Generic NCR5380' sources
-   were my main inspiration, with lots of reference to the IN2000
-   driver currently distributed in the kernel source. I also owe
-   much to a driver written by Hamish Macdonald for Linux-m68k(!).
-   And to Eric Wright for being an ALPHA guinea pig. And to Bill
-   Earnest for 2 tons of great input and information. And to David
-   Willmore for extensive 'bonnie' testing. And to Joe Mack for
-   continual testing and feedback.
-
-
-            John Shifflett    jshiffle@netcom.com
-
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- lx2.0/v2.0.21/linux/drivers/scsi/ncr53c8xx.c	Sun Sep  8 19:50:21 1996
+++ linux/drivers/scsi/ncr53c8xx.c	Mon Sep 30 08:54:10 1996
@@ -301,7 +301,7 @@
 **
 **	Linux 1.3.X allow to remap physical pages addresses greater than
 **	the highest physical memory address to kernel virtual pages.
-**	We must use vremap() to map the page and vfree() to unmap it.
+**	We must use ioremap() to map the page and iounmap() to unmap it.
 **	The memory base of ncr chips is set by the bios at a high physical
 **	address. Also we can map it, and MMIO is possible.
 */
@@ -310,13 +310,13 @@
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
 	u_long page_offs	= ((u_long) base) - page_base;
-	u_long page_remapped	= (u_long) vremap(page_base, page_offs+size);
+	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);
 
 	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) vfree((void *) (vaddr & PAGE_MASK));
+	if (vaddr) iounmap((void *) (vaddr & PAGE_MASK));
 }
 
 #else
@@ -547,7 +547,7 @@
 #define INB_OFF(o)         IOM_INB_OFF(o)
 #define INW(r)             IOM_INW(r)
 #define INL(r)             IOM_INL(r)
-#define INL_OFF(r)         IOM_INL_OFF(o)
+#define INL_OFF(o)         IOM_INL_OFF(o)
 
 #define OUTB(r, val)       IOM_OUTB(r, val)
 #define OUTW(r, val)       IOM_OUTW(r, val)
@@ -3587,7 +3587,7 @@
 #   ifdef SCSI_NCR_SHARE_IRQ
 	printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
 	        ncr_name(np), irq, (u_long) np);
-	if (request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, "53c8xx", np)) {
+	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT|SA_SHIRQ, "53c8xx", np)) {
 #   else
 	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx", NULL)) {
 #   endif
@@ -4790,6 +4790,11 @@
 	ncr_wakeup (np, code);
 
 	/*
+	**	Remove Reset, abort ...
+	*/
+	OUTB (nc_istat,  0      );
+
+	/*
 	**	Init chip.
 	*/
 /**	NCR53C810			**/
@@ -4838,8 +4843,6 @@
 	burstlen = 0xc0;
 #endif
 
-	OUTB (nc_istat,  0      );      /*  Remove Reset, abort ...	     */
-
 #ifdef SCSI_NCR_DISABLE_PARITY_CHECK
 	OUTB (nc_scntl0, 0xc0   );      /*  full arb., (no parity)           */
 #else
@@ -7636,7 +7639,6 @@
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 #   ifdef SCSI_NCR_SHARE_IRQ
                if (dev_id == &host_data->ncb_data)
-	       	    ncr_intr(&host_data->ncb_data);
 #   endif
 #endif
 	       ncr_intr(&host_data->ncb_data);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- lx2.0/v2.0.21/linux/drivers/scsi/scsi.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/scsi/scsi.c	Thu Sep 26 15:28:24 1996
@@ -652,6 +652,8 @@
     SDpnt->manufacturer = SCSI_MAN_SONY;
   else if (!strncmp (scsi_result + 8, "PIONEER", 7))
     SDpnt->manufacturer = SCSI_MAN_PIONEER;
+  else if (!strncmp (scsi_result + 8, "MATSHITA", 8))
+    SDpnt->manufacturer = SCSI_MAN_MATSHITA;
   else
     SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
 
@@ -2126,8 +2128,7 @@
 		  that the delay in internal_cmnd will guarantee at least a
 		  MIN_RESET_DELAY bus settle time.
 		*/
-		if ((host->last_reset < jiffies) || 
-		    (host->last_reset > (jiffies + 20 * HZ)))
+		if (host->last_reset - jiffies > 20UL * HZ)
 		  host->last_reset = jiffies;
 	    }
 	    else
@@ -2886,7 +2887,7 @@
 	
     new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
 
-    if (high_memory-1 > ISA_DMA_THRESHOLD)
+    if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
 	scsi_need_isa_bounce_buffers = 1;
     else
 	scsi_need_isa_bounce_buffers = 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- lx2.0/v2.0.21/linux/drivers/scsi/scsi.h	Mon Jul  8 10:41:07 1996
+++ linux/drivers/scsi/scsi.h	Thu Sep 26 15:26:55 1996
@@ -132,6 +132,7 @@
 #define SCSI_MAN_NEC_OLDCDR  3
 #define SCSI_MAN_SONY        4
 #define SCSI_MAN_PIONEER     5
+#define SCSI_MAN_MATSHITA    6
 
 /*
  *  As the scsi do command functions are intelligent, and may need to
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- lx2.0/v2.0.21/linux/drivers/scsi/sr.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/scsi/sr.c	Thu Sep 26 15:28:30 1996
@@ -545,8 +545,9 @@
 
     case SCSI_MAN_SONY: /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
     case SCSI_MAN_PIONEER:
+    case SCSI_MAN_MATSHITA:
 #ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER code\n");
+	printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER/MATSHITA code\n");
 #endif
 	get_sectorsize(MINOR(inode->i_rdev));	/* spinup (avoid timeout) */
 	memset(buf,0,40);
@@ -560,11 +561,11 @@
 	
 	if (rc != 0) {
             if (rc != 0x28000002) /* drop "not ready" */
-                printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER): 0x%x\n",rc);
+                printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER/MATSHITA): 0x%x\n",rc);
 	    break;
 	}
 	if ((rec[0] << 8) + rec[1] != 0x0a) {
-	    printk(KERN_INFO "sr_photocd: (SONY/PIONEER) Hmm, seems the CDROM doesn't support multisession CD's\n");
+	    printk(KERN_INFO "sr_photocd: (SONY/PIONEER/MATSHITA) Hmm, seems the CDROM doesn't support multisession CD's\n");
 	    no_multi = 1;
 	    break;
 	}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- lx2.0/v2.0.21/linux/drivers/scsi/u14-34f.c	Wed Jul 10 08:05:27 1996
+++ linux/drivers/scsi/u14-34f.c	Mon Sep 30 09:44:17 1996
@@ -322,7 +322,7 @@
    memset(cpp, 0, sizeof(struct mscp));
    cpp->opcode = OP_HOST_ADAPTER;
    cpp->xdir = DTD_IN;
-   cpp->data_address = (unsigned int) HD(j)->board_id;
+   cpp->data_address = virt_to_bus(HD(j)->board_id);
    cpp->data_len = sizeof(HD(j)->board_id);
    cpp->scsi_cdbs_len = 6;
    cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
@@ -338,7 +338,7 @@
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(virt_to_bus(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -568,13 +568,13 @@
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 
    for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = (unsigned int) sgpnt[k].address;
+      cpp->sglist[k].address = virt_to_bus(sgpnt[k].address);
       cpp->sglist[k].num_bytes = sgpnt[k].length;
       data_len += sgpnt[k].length;
       }
 
    cpp->use_sg = SCpnt->use_sg;
-   cpp->data_address = (unsigned int) cpp->sglist;
+   cpp->data_address = virt_to_bus(cpp->sglist);
    cpp->data_len = data_len;
 }
 
@@ -649,7 +649,7 @@
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = (unsigned int) SCpnt->sense_buffer;
+   cpp->sense_addr = virt_to_bus(SCpnt->sense_buffer);
    cpp->sense_len = sizeof SCpnt->sense_buffer;
 
    if (SCpnt->use_sg) {
@@ -657,7 +657,7 @@
       build_sg_list(cpp, SCpnt);
       }
    else {
-      cpp->data_address = (unsigned int)SCpnt->request_buffer;
+      cpp->data_address = virt_to_bus(SCpnt->request_buffer);
       cpp->data_len = SCpnt->request_bufflen;
       }
 
@@ -675,7 +675,7 @@
       }
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(virt_to_bus(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -901,7 +901,7 @@
 	 if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
 			      BN(j), HD(j)->iocount);
 
-	 spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
+	 spp = (struct mscp *)bus_to_virt(inl(sh[j]->io_port + REG_ICM));
 
 	 /* Clear interrupt pending flag */
 	 outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- lx2.0/v2.0.21/linux/drivers/sound/configure.c	Sat Jul 20 08:56:20 1996
+++ linux/drivers/sound/configure.c	Wed Sep 25 21:35:40 1996
@@ -735,11 +735,13 @@
    * IRQ and DMA settings
    */
 
+#if 0	/* Disable this broken question. */
   ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE",
 		  "I/O base for Audio Excel DSP 16",
 		  FMT_HEX,
 		  0x220,
 		  "220 or 240");
+#endif
 
   ask_int_choice (B (OPT_SB), "SBC_BASE",
 		  "I/O base for SB",
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- lx2.0/v2.0.21/linux/drivers/sound/dev_table.c	Sun Jun 30 11:43:53 1996
+++ linux/drivers/sound/dev_table.c	Mon Sep 30 10:02:06 1996
@@ -546,8 +546,10 @@
   audio_devs[num_audiodevs] = op;
   num = num_audiodevs++;
 
+#ifdef CONFIG_AUDIO
   DMAbuf_init ();
   audio_init ();
+#endif
   return num;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- lx2.0/v2.0.21/linux/drivers/sound/os.h	Wed Jul 10 14:19:25 1996
+++ linux/drivers/sound/os.h	Wed Sep 25 12:21:48 1996
@@ -25,6 +25,7 @@
 #include <asm/dma.h>
 #include <linux/wait.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/utsname.h>
diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- lx2.0/v2.0.21/linux/drivers/sound/soundcard.c	Wed Aug 21 09:18:09 1996
+++ linux/drivers/sound/soundcard.c	Wed Sep 25 14:33:57 1996
@@ -289,7 +289,7 @@
 	      size, dmap->bytes_in_use);
     }
 
-  if (remap_page_range (vma_get_start (vma), (unsigned long)dmap->raw_buf,
+  if (remap_page_range (vma_get_start (vma), virt_to_phys(dmap->raw_buf),
 			vma_get_end (vma) - vma_get_start (vma),
 			vma_get_page_prot (vma)))
     return -EAGAIN;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- lx2.0/v2.0.21/linux/fs/binfmt_aout.c	Sat Aug 17 21:19:28 1996
+++ linux/fs/binfmt_aout.c	Sat Sep 28 23:53:58 1996
@@ -60,8 +60,8 @@
 while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
 
 #define DUMP_SEEK(offset) \
-if (file.f_op->lseek) { \
-	if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
+if (file.f_op->llseek) { \
+	if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \
  		goto close_coredump; \
 } else file.f_pos = (offset)		
 
@@ -204,7 +204,7 @@
  */
 static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
 {
-	unsigned long *argv,*envp;
+	char **argv, **envp;
 	unsigned long * sp;
 	int argc = bprm->argc;
 	int envc = bprm->envc;
@@ -224,12 +224,12 @@
 	put_user(0x3e9, --sp);
 #endif
 	sp -= envc+1;
-	envp = sp;
+	envp = (char **) sp;
 	sp -= argc+1;
-	argv = sp;
+	argv = (char **) sp;
 #if defined(__i386__) || defined(__mc68000__)
-	put_user(envp,--sp);
-	put_user(argv,--sp);
+	put_user((unsigned long) envp,--sp);
+	put_user((unsigned long) argv,--sp);
 #endif
 	put_user(argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
@@ -423,8 +423,8 @@
 		return -EACCES;
 
 	/* Seek into the file */
-	if (file->f_op->lseek) {
-		if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0)
+	if (file->f_op->llseek) {
+		if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
 			return -ENOEXEC;
 	} else
 		file->f_pos = 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- lx2.0/v2.0.21/linux/fs/binfmt_elf.c	Sun Sep  8 19:50:21 1996
+++ linux/fs/binfmt_elf.c	Sat Sep 28 23:53:41 1996
@@ -108,7 +108,8 @@
 				  unsigned long load_addr,
 				  unsigned long interp_load_addr, int ibcs)
 {
-	unsigned long *argv, *envp, *dlinfo;
+	char **argv, **envp;
+	unsigned long *dlinfo;
 	unsigned long *sp;
 
 	/*
@@ -118,12 +119,12 @@
 	sp -= exec ? DLINFO_ITEMS*2 : 2;
 	dlinfo = sp;
 	sp -= envc+1;
-	envp = sp;
+	envp = (char **) sp;
 	sp -= argc+1;
-	argv = sp;
+	argv = (char **) sp;
 	if (!ibcs) {
-		put_user(envp,--sp);
-		put_user(argv,--sp);
+		put_user((unsigned long) envp,--sp);
+		put_user((unsigned long) argv,--sp);
 	}
 
 #define NEW_AUX_ENT(id, val) \
@@ -154,13 +155,13 @@
 		put_user(p,argv++);
 		while (get_user(p++)) /* nothing */ ;
 	}
-	put_user(0,argv);
+	put_user(NULL, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		put_user(p,envp++);
 		while (get_user(p++)) /* nothing */ ;
 	}
-	put_user(0,envp);
+	put_user(NULL, envp);
 	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
@@ -754,8 +755,8 @@
 		return -EACCES;
 
 	/* seek to the beginning of the file */
-	if (file->f_op->lseek) {
-		if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0)
+	if (file->f_op->llseek) {
+		if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
 			return -ENOEXEC;
 	} else
 		file->f_pos = 0;
@@ -863,8 +864,8 @@
 
 static int dump_seek(struct file *file, off_t off)
 {
-	if (file->f_op->lseek) {
-		if (file->f_op->lseek(file->f_inode, file, off, 0) != off)
+	if (file->f_op->llseek) {
+		if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
 			return 0;
 	} else
 		file->f_pos = off;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/block_dev.c linux/fs/block_dev.c
--- lx2.0/v2.0.21/linux/fs/block_dev.c	Mon May  6 12:26:13 1996
+++ linux/fs/block_dev.c	Sat Sep 28 23:49:51 1996
@@ -20,7 +20,8 @@
 #define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
 #define NBUF 64
 
-int block_write(struct inode * inode, struct file * filp, const char * buf, int count)
+long block_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	int blocksize, blocksize_bits, i, j, buffercount,write_error;
 	int block, blocks;
@@ -157,7 +158,8 @@
 	return written;
 }
 
-int block_read(struct inode * inode, struct file * filp, char * buf, int count)
+long block_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	unsigned int block;
 	loff_t offset;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/buffer.c linux/fs/buffer.c
--- lx2.0/v2.0.21/linux/fs/buffer.c	Fri Sep 20 17:00:35 1996
+++ linux/fs/buffer.c	Wed Sep 25 12:15:57 1996
@@ -30,6 +30,7 @@
 #include <linux/swapctl.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -1865,7 +1866,7 @@
 {
 	int i;
 	int isize = BUFSIZE_INDEX(BLOCK_SIZE);
-	long memsize = MAP_NR(high_memory) << PAGE_SHIFT;
+	long memsize = max_mapnr << PAGE_SHIFT;
 
 	if (memsize >= 64*1024*1024)
 		nr_hash = 65521;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/dquot.c linux/fs/dquot.c
--- lx2.0/v2.0.21/linux/fs/dquot.c	Mon May 13 07:36:19 1996
+++ linux/fs/dquot.c	Sat Sep 28 23:54:26 1996
@@ -222,8 +222,8 @@
 		return;
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
-	if (filp->f_op->lseek) {
-		if (filp->f_op->lseek(filp->f_inode, filp,
+	if (filp->f_op->llseek) {
+		if (filp->f_op->llseek(filp->f_inode, filp,
 		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
 			up(&dquot->dq_mnt->mnt_sem);
 			unlock_dquot(dquot);
@@ -252,8 +252,8 @@
 		return;
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
-	if (filp->f_op->lseek) {
-		if (filp->f_op->lseek(filp->f_inode, filp,
+	if (filp->f_op->llseek) {
+		if (filp->f_op->llseek(filp->f_inode, filp,
 		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
 			up(&dquot->dq_mnt->mnt_sem);
 			unlock_dquot(dquot);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/exec.c linux/fs/exec.c
--- lx2.0/v2.0.21/linux/fs/exec.c	Wed Sep 11 17:57:15 1996
+++ linux/fs/exec.c	Sat Sep 28 23:50:26 1996
@@ -338,8 +338,8 @@
 			goto end_readexec;
 	if (!file.f_op || !file.f_op->read)
 		goto close_readexec;
-	if (file.f_op->lseek) {
-		if (file.f_op->lseek(inode,&file,offset,0) != offset)
+	if (file.f_op->llseek) {
+		if (file.f_op->llseek(inode,&file,offset,0) != offset)
  			goto close_readexec;
 	} else
 		file.f_pos = offset;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/ext/dir.c linux/fs/ext/dir.c
--- lx2.0/v2.0.21/linux/fs/ext/dir.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/ext/dir.c	Mon Sep 30 11:01:41 1996
@@ -20,7 +20,8 @@
 #include <linux/ext_fs.h>
 #include <linux/stat.h>
 
-static int ext_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long ext_dir_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/ext/file.c linux/fs/ext/file.c
--- lx2.0/v2.0.21/linux/fs/ext/file.c	Mon May  6 12:26:13 1996
+++ linux/fs/ext/file.c	Mon Sep 30 11:01:20 1996
@@ -32,8 +32,8 @@
 #include <linux/fs.h>
 #include <linux/ext_fs.h>
 
-static int ext_file_read(struct inode *, struct file *, char *, int);
-static int ext_file_write(struct inode *, struct file *, const char *, int);
+static long ext_file_read(struct inode *, struct file *, char *, unsigned long);
+static long ext_file_write(struct inode *, struct file *, const char *, unsigned long);
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -72,7 +72,8 @@
 	NULL			/* permission */
 };
 
-static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long ext_file_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	int read,left,chars;
 	int block, blocks, offset;
@@ -197,7 +198,8 @@
 	return read;
 }
 
-static int ext_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long ext_file_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	off_t pos;
 	int written,c;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- lx2.0/v2.0.21/linux/fs/ext2/dir.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/ext2/dir.c	Sat Sep 28 23:24:16 1996
@@ -23,8 +23,8 @@
 #include <linux/sched.h>
 #include <linux/stat.h>
 
-static int ext2_dir_read (struct inode * inode, struct file * filp,
-			    char * buf, int count)
+static long ext2_dir_read (struct inode * inode, struct file * filp,
+			    char * buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- lx2.0/v2.0.21/linux/fs/ext2/file.c	Tue Feb 20 10:28:13 1996
+++ linux/fs/ext2/file.c	Mon Sep 30 08:49:14 1996
@@ -36,7 +36,7 @@
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 
-static int ext2_file_write (struct inode *, struct file *, const char *, int);
+static long ext2_file_write (struct inode *, struct file *, const char *, unsigned long);
 static void ext2_release_file (struct inode *, struct file *);
 
 /*
@@ -80,8 +80,8 @@
 	NULL			/* smap */
 };
 
-static int ext2_file_write (struct inode * inode, struct file * filp,
-			    const char * buf, int count)
+static long ext2_file_write (struct inode * inode, struct file * filp,
+			    const char * buf, unsigned long count)
 {
 	const loff_t two_gb = 2147483647;
 	loff_t pos;
@@ -140,9 +140,9 @@
 				written = err;
 			break;
 		}
+		if (c > count)
+			c = count;
 		count -= c;
-		if (count < 0)
-			c += count;
 		if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
 			ll_rw_block (READ, 1, &bh);
 			wait_on_buffer (bh);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- lx2.0/v2.0.21/linux/fs/fat/dir.c	Fri May 10 07:54:52 1996
+++ linux/fs/fat/dir.c	Sat Sep 28 23:39:53 1996
@@ -29,7 +29,8 @@
 
 #define PRINTK(X)
 
-static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
+static long fat_dir_read(struct inode * inode,struct file * filp,
+	char * buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/fat/file.c linux/fs/fat/file.c
--- lx2.0/v2.0.21/linux/fs/fat/file.c	Fri May 10 07:54:52 1996
+++ linux/fs/fat/file.c	Sat Sep 28 23:39:17 1996
@@ -152,11 +152,11 @@
 /*
 	Read a file into user space
 */
-int fat_file_read(
+long fat_file_read(
 	struct inode *inode,
 	struct file *filp,
 	char *buf,
-	int count)
+	unsigned long count)
 {
 	struct super_block *sb = inode->i_sb;
 	char *start = buf;
@@ -175,7 +175,7 @@
 		printk("fat_file_read: mode = %07o\n",inode->i_mode);
 		return -EINVAL;
 	}
-	if (filp->f_pos >= inode->i_size || count <= 0) return 0;
+	if (filp->f_pos >= inode->i_size || count == 0) return 0;
 	/*
 		Tell the buffer cache which block we expect to read in advance
 		Since we are limited with the stack, we preread only MSDOS_PREFETCH
@@ -269,11 +269,11 @@
 /*
 	Write to a file either from user space
 */
-int fat_file_write(
+long fat_file_write(
 	struct inode *inode,
 	struct file *filp,
 	const char *buf,
-	int count)
+	unsigned long count)
 {
 	struct super_block *sb = inode->i_sb;
 	int sector,offset,size,left,written;
@@ -301,7 +301,7 @@
  */
 	if (filp->f_flags & O_APPEND)
 		filp->f_pos = inode->i_size;
-	if (count <= 0)
+	if (count == 0)
 		return 0;
 	error = carry = 0;
 	for (start = buf; count || carry; count -= size) {
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- lx2.0/v2.0.21/linux/fs/fat/misc.c	Fri May 10 07:54:52 1996
+++ linux/fs/fat/misc.c	Thu Sep 26 15:28:30 1996
@@ -244,6 +244,9 @@
 	    month < 2 ? 1 : 0)+3653);
 			/* days since 1.1.70 plus 80's leap day */
 	secs += sys_tz.tz_minuteswest*60;
+	if (sys_tz.tz_dsttime) {
+	    secs -= 3600;
+	}
 	return secs;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- lx2.0/v2.0.21/linux/fs/hpfs/hpfs_fs.c	Tue Feb 20 10:28:13 1996
+++ linux/fs/hpfs/hpfs_fs.c	Mon Sep 30 11:15:00 1996
@@ -144,7 +144,7 @@
 
 /* file ops */
 
-static int hpfs_file_read(struct inode *, struct file *, char *, int);
+static long hpfs_file_read(struct inode *, struct file *, char *, unsigned long);
 static secno hpfs_bmap(struct inode *, unsigned);
 
 static const struct file_operations hpfs_file_ops =
@@ -185,8 +185,8 @@
 
 /* directory ops */
 
-static int hpfs_dir_read(struct inode *inode, struct file *filp,
-			 char *buf, int count);
+static long hpfs_dir_read(struct inode *inode, struct file *filp,
+			  char *buf, unsigned long count);
 static int hpfs_readdir(struct inode *inode, struct file *filp,
 			void *dirent, filldir_t filldir);
 static int hpfs_lookup(struct inode *, const char *, int, struct inode **);
@@ -321,7 +321,7 @@
 static inline time_t local_to_gmt(time_t t)
 {
 	extern struct timezone sys_tz;
-	return t + sys_tz.tz_minuteswest * 60;
+	return t + sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 : 0);
 }
 
 /* super block ops */
@@ -878,8 +878,8 @@
  * read.  Read the bytes, put them in buf, return the count.
  */
 
-static int hpfs_file_read(struct inode *inode, struct file *filp,
-			  char *buf, int count)
+static long hpfs_file_read(struct inode *inode, struct file *filp,
+			  char *buf, unsigned long count)
 {
 	unsigned q, r, n, n0;
 	struct buffer_head *bh;
@@ -1579,8 +1579,8 @@
 	return 0;
 }
 
-static int hpfs_dir_read(struct inode *inode, struct file *filp,
-			 char *buf, int count)
+static long hpfs_dir_read(struct inode *inode, struct file *filp,
+			  char *buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/locks.c linux/fs/locks.c
--- lx2.0/v2.0.21/linux/fs/locks.c	Fri Sep 20 17:00:35 1996
+++ linux/fs/locks.c	Fri Sep 27 07:09:58 1996
@@ -28,22 +28,22 @@
  *  dynamically with kmalloc()/kfree().
  *  Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995
  *
- *  Implemented two lock personalities - F_FLOCK and F_POSIX.
+ *  Implemented two lock personalities - FL_FLOCK and FL_POSIX.
  *
- *  F_POSIX locks are created with calls to fcntl() and lockf() through the
+ *  FL_POSIX locks are created with calls to fcntl() and lockf() through the
  *  fcntl() system call. They have the semantics described above.
  *
- *  F_FLOCK locks are created with calls to flock(), through the flock()
+ *  FL_FLOCK locks are created with calls to flock(), through the flock()
  *  system call, which is new. Old C libraries implement flock() via fcntl()
  *  and will continue to use the old, broken implementation.
  *
- *  F_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated
+ *  FL_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated
  *  with a file pointer (filp). As a result they can be shared by a parent
  *  process and its children after a fork(). They are removed when the last
  *  file descriptor referring to the file pointer is closed (unless explicitly
  *  unlocked). 
  *
- *  F_FLOCK locks never deadlock, an existing lock is always removed before
+ *  FL_FLOCK locks never deadlock, an existing lock is always removed before
  *  upgrading from shared to exclusive (or vice versa). When this happens
  *  any processes blocked by the current lock are woken up and allowed to
  *  run before the new lock is applied.
@@ -76,15 +76,24 @@
  *  flock() and fcntl().
  *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
  *
- *  Allow only one type of locking scheme (F_POSIX or F_FLOCK) to be in use
- *  for a given file at a time. Changed the CONFIG_MANDATORY_OPTION scheme to
+ *  Allow only one type of locking scheme (FL_POSIX or FL_FLOCK) to be in use
+ *  for a given file at a time. Changed the CONFIG_LOCK_MANDATORY scheme to
  *  guarantee sensible behaviour in the case where file system modules might
  *  be compiled with different options than the kernel itself.
  *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
  *
- *  Added a couple of missing wake_up() calls.
+ *  Added a couple of missing wake_up() calls. Thanks to Thomas Meckel
+ *  (Thomas.Meckel@mni.fh-giessen.de) for spotting this.
  *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
  *
+ *  Changed FL_POSIX locks to use the block list in the same way as FL_FLOCK
+ *  locks. Changed process synchronisation to avoid dereferencing locks that
+ *  have already been freed.
+ *  Andy Walker (andy@lysaker.kvaerner.no), Sep 21, 1996.
+ *
+ *  Made the block list a circular list to minimise searching in the list.
+ *  Andy Walker (andy@lysaker.kvaerner.no), Sep 25, 1996.
+ *
  *  TODO: Do not honour mandatory locks on remote file systems. This matches
  *        the SVR4 semantics and neatly sidesteps a pile of awkward issues that
  *        would otherwise have to be addressed.
@@ -124,70 +133,101 @@
 
 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 **fl, unsigned int wait);
+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 struct file_lock *file_lock_table = NULL;
-static struct file_lock *unused_file_locks = NULL;
 
-/*
- * Free lock not inserted in any queue
- *
- * Careful! We can't just "kfree()" it: there may be other processes
- * that have yet to remove themselves from the wait queues. Thus the
- * internal memory management.
+/* Free lock not inserted in any queue.
  */
 static inline void locks_free_lock(struct file_lock *fl)
 {
-	struct file_lock *next = unused_file_locks;
-	unused_file_locks = fl;
-	fl->fl_next = next;
-}
-
-/* Add lock fl to the blocked list pointed to by block.
- * We search to the end of the existing list and insert the the new
- * struct. This ensures processes will be woken up in the order they
- * blocked.
- * NOTE: nowhere does the documentation insist that processes be woken
- * up in this order, but it seems like the reasonable thing to do.
- * If the blocked list gets long then this search could get expensive,
- * in which case we could consider waking the processes up in reverse
- * order, or making the blocked list a doubly linked circular list.
- * 
- * This functions are called only from one place (flock_lock_file)
- * so they are inlined now. -- Dmitry Gorodchanin 02/09/96.
- */
-
-static inline void locks_insert_block(struct file_lock *bfl, 
-				      struct file_lock *fl)
+	if (waitqueue_active(&fl->fl_wait))
+		panic("Aarggh: attempting to free lock with active wait queue - shoot Andy");
+
+	if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL)
+		panic("Aarggh: attempting to free lock with active block list - shoot Andy");
+		
+	kfree(fl);
+	return;
+}
+
+/* Insert waiter into blocker's block list.
+ * We use a circular list so that processes can be easily woken up in
+ * the order they blocked. The documentation doesn't require this but
+ * it seems seems like the reasonable thing to do.
+ */
+static inline void locks_insert_block(struct file_lock *blocker, 
+				      struct file_lock *waiter)
 {
-	while (bfl->fl_block != NULL) {
-		bfl = bfl->fl_block;
-	}
+	struct file_lock *prevblock;
 
-	bfl->fl_block = fl;
-	fl->fl_block = NULL;
+	if (blocker->fl_prevblock == NULL)
+		/* No previous waiters - list is empty */
+		prevblock = blocker;
+	else
+		/* Previous waiters exist - add to end of list */
+		prevblock = blocker->fl_prevblock;
+
+	prevblock->fl_nextblock = waiter;
+	blocker->fl_prevblock = waiter;
+	waiter->fl_nextblock = blocker;
+	waiter->fl_prevblock = prevblock;
 	
 	return;
 }
 
-static inline void locks_delete_block(struct file_lock *bfl,
-				      struct file_lock *fl)
+/* Remove waiter from blocker's block list.
+ * When blocker ends up pointing to itself then the list is empty.
+ */
+static inline void locks_delete_block(struct file_lock *blocker,
+				      struct file_lock *waiter)
 {
-	struct file_lock *tfl;
+	struct file_lock *nextblock;
+	struct file_lock *prevblock;
 	
-	while ((tfl = bfl->fl_block) != NULL) {
-		if (tfl == fl) {
-			bfl->fl_block = fl->fl_block;
-			fl->fl_block = NULL;
-			return;
-		}
-		bfl = tfl;
+	nextblock = waiter->fl_nextblock;
+	prevblock = waiter->fl_prevblock;
+
+	if (nextblock == NULL)
+		return;
+	
+	nextblock->fl_prevblock = prevblock;
+	prevblock->fl_nextblock = nextblock;
+
+	waiter->fl_prevblock = waiter->fl_nextblock = NULL;
+	if (blocker->fl_nextblock == blocker)
+		/* No more locks on blocker's blocked list */
+		blocker->fl_prevblock = blocker->fl_nextblock = NULL;
+	return;
+}
+
+/* Wake up processes blocked waiting for blocker.
+ * If told to wait then schedule the processes until the block list
+ * is empty, otherwise empty the block list ourselves.
+ */
+static inline void locks_wake_up_blocks(struct file_lock *blocker,
+					unsigned int wait)
+{
+	struct file_lock *waiter;
+
+	while ((waiter = blocker->fl_nextblock) != NULL) {
+		wake_up(&waiter->fl_wait);
+		if (wait)
+			/* Let the blocked process remove waiter from the
+			 * block list when it gets scheduled.
+			 */
+			schedule();
+		else
+			/* Remove waiter from the block list, because by the
+			 * time it wakes up blocker won't exist any more.
+			 */
+			locks_delete_block(blocker, waiter);
 	}
 	return;
 }
 
-/* flock() system call entry point. Apply a FLOCK style lock to
+/* flock() system call entry point. Apply a FL_FLOCK style lock to
  * an open file descriptor.
  */
 asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
@@ -203,8 +243,8 @@
 	
 	if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
 		return (-EBADF);
-	
-	return (flock_lock_file(filp, &file_lock, cmd & LOCK_UN ? 0 : cmd & LOCK_NB ? 0 : 1));
+
+	return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1));
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -231,7 +271,7 @@
 	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
 		return (-EINVAL);
 
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_POSIX)) { 
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_POSIX)) { 
 		while (fl != NULL) {
 			if (posix_locks_conflict(&file_lock, fl)) {
 				flock.l_pid = fl->fl_owner->pid;
@@ -283,7 +323,8 @@
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
 	 */
-	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) {
+	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
+	    inode->i_mmap) {
 		struct vm_area_struct *vma = inode->i_mmap;
 		do {
 			if (vma->vm_flags & VM_MAYSHARE)
@@ -343,7 +384,7 @@
 	 * close on that file.
 	 */
 	if ((fl = filp->f_inode->i_flock) != NULL) {
-		if (fl->fl_flags & F_POSIX)
+		if (fl->fl_flags & FL_POSIX)
 			posix_remove_locks(&filp->f_inode->i_flock, task);
 		else
 			flock_remove_locks(&filp->f_inode->i_flock, filp);
@@ -395,14 +436,14 @@
 int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
 		      unsigned int offset, unsigned int count)
 {
-#ifdef CONFIG_LOCK_MANDATORY	 
+#ifdef CONFIG_LOCK_MANDATORY
 	/* Candidates for mandatory locking have the setgid bit set
 	 * but no group execute bit -  an otherwise meaningless combination.
 	 */
 	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
 		return (locks_mandatory_area(read_write, inode, filp, offset,
 					     count));
-#endif					     
+#endif
 	return (0);
 }
 
@@ -413,7 +454,7 @@
 
 	/* Search the lock list for this inode for any POSIX locks.
 	 */
-	if ((fl = inode->i_flock) && (fl->fl_flags & F_FLOCK))
+	if ((fl = inode->i_flock) == NULL || (fl->fl_flags & FL_FLOCK))
 		return (0);
 	
 	while (fl != NULL) {
@@ -431,11 +472,25 @@
 {
 #ifdef CONFIG_LOCK_MANDATORY	
 	struct file_lock *fl;
+	struct file_lock tfl;
+
+	tfl.fl_file = filp;
+	tfl.fl_nextlink = NULL;
+	tfl.fl_prevlink = NULL;
+	tfl.fl_next = NULL;
+	tfl.fl_nextblock = NULL;
+	tfl.fl_prevblock = NULL;
+	tfl.fl_flags = FL_POSIX | FL_ACCESS;
+	tfl.fl_owner = current;
+	tfl.fl_wait = NULL;
+	tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
+	tfl.fl_start = offset;
+	tfl.fl_end = offset + count - 1;
 
 repeat:
-	/* Check that there are locks, and that they're not F_FLOCK locks.
+	/* Check that there are locks, and that they're not FL_FLOCK locks.
 	 */
-	if ((fl = inode->i_flock) && (fl->fl_flags & F_FLOCK))
+	if ((fl = inode->i_flock) == NULL || (fl->fl_flags & FL_FLOCK))
 		return (0);
 	
 	/*
@@ -459,7 +514,11 @@
 				return (-ERESTARTSYS);
 			if (posix_locks_deadlock(current, fl->fl_owner))
 				return (-EDEADLK);
-			interruptible_sleep_on(&fl->fl_wait);
+
+			locks_insert_block(fl, &tfl);
+			interruptible_sleep_on(&tfl.fl_wait);
+			locks_delete_block(fl, &tfl);
+
 			if (current->signal & ~current->blocked)
 				return (-ERESTARTSYS);
 			/*
@@ -485,7 +544,7 @@
 {
 	off_t start;
 
-	fl->fl_flags = F_POSIX;
+	fl->fl_flags = FL_POSIX;
 
 	switch (l->l_type) {
 	case F_RDLCK :
@@ -495,11 +554,11 @@
 		break;
 	case F_SHLCK :
 		fl->fl_type = F_RDLCK;
-		fl->fl_flags |= F_BROKEN;
+		fl->fl_flags |= FL_BROKEN;
 		break;
 	case F_EXLCK :
 		fl->fl_type = F_WRLCK;
-		fl->fl_flags |= F_BROKEN;
+		fl->fl_flags |= FL_BROKEN;
 		break;
 	default :
 		return (0);
@@ -528,7 +587,7 @@
 	fl->fl_file = filp;
 	fl->fl_owner = current;
 	fl->fl_wait = NULL;		/* just for cleanliness */
-	
+
 	return (1);
 }
 
@@ -555,7 +614,7 @@
 		return (0);
 	}
 
-	fl->fl_flags = F_FLOCK;
+	fl->fl_flags = FL_FLOCK;
 	fl->fl_start = 0;
 	fl->fl_end = OFFSET_MAX;
 	fl->fl_file = filp;
@@ -637,27 +696,23 @@
 static int posix_locks_deadlock(struct task_struct *my_task,
 				struct task_struct *blocked_task)
 {
-	struct wait_queue *dlock_wait;
 	struct file_lock *fl;
+	struct file_lock *bfl;
 
 next_task:
 	if (my_task == blocked_task)
 		return (1);
 	for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
-		struct wait_queue *head;
-		if (fl->fl_owner == NULL || fl->fl_wait == NULL)
+		if (fl->fl_owner == NULL || fl->fl_nextblock == NULL)
 			continue;
-		head = WAIT_QUEUE_HEAD(&fl->fl_wait);
-		dlock_wait = fl->fl_wait;
-		while (dlock_wait != head) {
-			if (dlock_wait->task == blocked_task) {
+		for (bfl = fl->fl_nextblock; bfl != fl; bfl = bfl->fl_nextblock) {
+			if (bfl->fl_owner == blocked_task) {
 				if (fl->fl_owner == my_task) {
 					return (1);
 				}
 				blocked_task = fl->fl_owner;
 				goto next_task;
 			}
-			dlock_wait = dlock_wait->next;
 		}
 	}
 	return (0);
@@ -676,7 +731,7 @@
 
 	before = &filp->f_inode->i_flock;
 
-	if ((fl = *before) && (fl->fl_flags & F_POSIX))
+	if ((fl = *before) && (fl->fl_flags & FL_POSIX))
 		return (-EBUSY);
 
 	while ((fl = *before) != NULL) {
@@ -698,7 +753,7 @@
 	if ((new_fl = locks_alloc_lock(caller)) == NULL)
 		return (-ENOLCK);
 repeat:
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_POSIX)) {
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_POSIX)) {
 		locks_free_lock(new_fl);
 		return (-EBUSY);
 	}
@@ -720,7 +775,7 @@
 			}
 			locks_insert_block(fl, new_fl);
 			interruptible_sleep_on(&new_fl->fl_wait);
-			wake_up(&new_fl->fl_wait);
+			locks_delete_block(fl, new_fl);
 			if (current->signal & ~current->blocked) {
 				/* If we are here, than we were awakened
 				 * by a signal, so new_fl is still in the
@@ -728,7 +783,6 @@
 				 * new_fl and then free it.
 				 * 	Dmitry Gorodchanin 09/02/96.
 				 */
-				locks_delete_block(fl, new_fl);
 				locks_free_lock(new_fl);
 				return (-ERESTARTSYS);
 			}
@@ -763,7 +817,7 @@
 	int added = 0;
 
 repeat:
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_FLOCK))
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_FLOCK))
 		return (-EBUSY);
 
 	if (caller->fl_type != F_UNLCK) {
@@ -775,7 +829,9 @@
 					return (-ERESTARTSYS);
 				if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
 					return (-EDEADLK);
-				interruptible_sleep_on(&fl->fl_wait);
+				locks_insert_block(fl, caller);
+				interruptible_sleep_on(&caller->fl_wait);
+				locks_delete_block(fl, caller);
 				if (current->signal & ~current->blocked)
 					return (-ERESTARTSYS);
 				goto repeat;
@@ -862,7 +918,7 @@
 				 * as the change in lock type might satisfy
 				 * their needs.
 				 */
-				wake_up(&fl->fl_wait);
+				locks_wake_up_blocks(fl, 0);
 				fl->fl_start = caller->fl_start;
 				fl->fl_end = caller->fl_end;
 				fl->fl_type = caller->fl_type;
@@ -897,52 +953,47 @@
 			locks_insert_lock(before, left);
 		}
 		right->fl_start = caller->fl_end + 1;
-		wake_up(&right->fl_wait);
+		locks_wake_up_blocks(right, 0);
 	}
 	if (left) {
 		left->fl_end = caller->fl_start - 1;
-		wake_up(&left->fl_wait);
+		locks_wake_up_blocks(left, 0);
 	}
 	return (0);
 }
 
-/* Allocate memory for a new lock and initialize its fields from
- * fl. The lock is not inserted into any lists until locks_insert_lock()
- * or locks_insert_block() are called.
+/* Allocate new lock.
+ * Initialize its fields from fl. The lock is not inserted into any
+ * lists until locks_insert_lock() or locks_insert_block() are called.
  */
-
 static struct file_lock *locks_alloc_lock(struct file_lock *fl)
 {
-	struct file_lock *retval;
+	struct file_lock *tmp;
 
-	retval = unused_file_locks;
-	if (retval) {
-		unused_file_locks = retval->fl_next;
-		goto init_file_lock;
-	}
-	retval = (struct file_lock *)
-		kmalloc(sizeof(struct file_lock), GFP_ATOMIC);
-	if (retval) {
-		retval->fl_wait = NULL;
-init_file_lock:
-		retval->fl_next = NULL;
-		retval->fl_nextlink = NULL;
-		retval->fl_prevlink = NULL;
-		retval->fl_block = NULL;
-		retval->fl_owner = fl->fl_owner;
-		retval->fl_file = fl->fl_file;
-		retval->fl_flags = fl->fl_flags;
-		retval->fl_type = fl->fl_type;
-		retval->fl_start = fl->fl_start;
-		retval->fl_end = fl->fl_end;		
-	}
-	return retval;
+	/* Okay, let's make a new file_lock structure... */
+	if ((tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock),
+					       GFP_ATOMIC)) == NULL)
+		return (tmp);
+
+	tmp->fl_nextlink = NULL;
+	tmp->fl_prevlink = NULL;
+	tmp->fl_next = NULL;
+	tmp->fl_nextblock = NULL;
+	tmp->fl_prevblock = NULL;
+	tmp->fl_flags = fl->fl_flags;
+	tmp->fl_owner = fl->fl_owner;
+	tmp->fl_file = fl->fl_file;
+	tmp->fl_wait = NULL;
+	tmp->fl_type = fl->fl_type;
+	tmp->fl_start = fl->fl_start;
+	tmp->fl_end = fl->fl_end;
+
+	return (tmp);
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
  * by pos. At the same time add the lock to the global file lock list.
  */
-
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 {
 	fl->fl_nextlink = file_lock_table;
@@ -957,43 +1008,32 @@
 }
 
 /* Delete a lock and free it.
- * First remove our lock from the lock lists. Then remove all the blocked
- * locks from our blocked list, waking up the processes that own them. If
- * told to wait, then sleep on each of these lock's wait queues. Each
- * blocked process will wake up and immediately wake up its own wait queue
- * allowing us to be scheduled again. Lastly, wake up our own wait queue
- * before freeing the file_lock structure.
+ * First remove our lock from the active lock lists. Then call
+ * locks_wake_up_blocks() to wake up processes that are blocked
+ * waiting for this lock. Finally free the lock structure.
  */
-
-static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
+static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
 {
-	struct file_lock *fl;
-	struct file_lock *pfl;
-	struct file_lock *nfl;
+	struct file_lock *thisfl;
+	struct file_lock *prevfl;
+	struct file_lock *nextfl;
 	
-	fl = *fl_p;
-	*fl_p = fl->fl_next;
-	pfl = fl->fl_prevlink;
-	nfl = fl->fl_nextlink;
+	thisfl = *thisfl_p;
+	*thisfl_p = thisfl->fl_next;
+
+	prevfl = thisfl->fl_prevlink;
+	nextfl = thisfl->fl_nextlink;
 
-	if (nfl != NULL)
-		nfl->fl_prevlink = pfl;
+	if (nextfl != NULL)
+		nextfl->fl_prevlink = prevfl;
 
-	if (pfl != NULL)
-		pfl->fl_nextlink = nfl;
+	if (prevfl != NULL)
+		prevfl->fl_nextlink = nextfl;
 	else
-		file_lock_table = nfl;
+		file_lock_table = nextfl;
 	
-	while ((nfl = fl->fl_block) != NULL) {
-		fl->fl_block = nfl->fl_block;
-		nfl->fl_block = NULL;
-		wake_up(&nfl->fl_wait);
-		if (wait)
-			sleep_on(&nfl->fl_wait);
-	}
-
-	wake_up(&fl->fl_wait);
-	locks_free_lock(fl);
+	locks_wake_up_blocks(thisfl, wait);
+	locks_free_lock(thisfl);
 
 	return;
 }
@@ -1001,18 +1041,21 @@
 
 static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
 {
-	struct wait_queue *wt;
+	struct inode *inode;
+
+	inode = fl->fl_file->f_inode;
 
 	p += sprintf(p, "%d:%s ", id, pfx);
-	if (fl->fl_flags & F_POSIX) {
+	if (fl->fl_flags & FL_POSIX) {
 #ifdef CONFIG_LOCK_MANDATORY	 
 		p += sprintf(p, "%s %s ",
-			     (fl->fl_flags & F_BROKEN) ? "BROKEN" : "POSIX ",
-			     ((fl->fl_file->f_inode->i_mode & (S_IXGRP | S_ISGID))
-			      == S_ISGID) ? "MANDATORY" : "ADVISORY ");
+			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" :
+			     ((fl->fl_flags & FL_BROKEN) ? "BROKEN" : "POSIX "),
+			     ((inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
+			     "MANDATORY" : "ADVISORY ");
 #else
 		p += sprintf(p, "%s ADVISORY ",
-			     (fl->fl_flags & F_BROKEN) ? "BROKEN" : "POSIX ");
+			     (fl->fl_flags & FL_BROKEN) ? "BROKEN" : "POSIX ");
 #endif
 	}
 	else {
@@ -1021,20 +1064,11 @@
 	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
 	p += sprintf(p, "%d %s:%ld %ld %ld ",
 		     fl->fl_owner ? fl->fl_owner->pid : 0,
-		     kdevname(fl->fl_file->f_inode->i_dev),
-		     fl->fl_file->f_inode->i_ino, fl->fl_start,
+		     kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
 		     fl->fl_end);
-	p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n%d:%s",
+	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_block, id, pfx);
-	if ((wt = fl->fl_wait) != NULL) {
-		struct wait_queue *head = WAIT_QUEUE_HEAD(&fl->fl_wait);
-		while (wt != head) {
-			p += sprintf(p, " %d", wt->task->pid);
-			wt = wt->next;
-		}
-	}
-	p += sprintf(p, "\n");
+		     (long)fl->fl_next, (long)fl->fl_nextblock);
 	return (p);
 }
 
@@ -1048,8 +1082,11 @@
 	p = buf;
 	for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
 		p = lock_get_status(fl, p, i, "");
-		for (bfl = fl; bfl->fl_block != NULL; bfl = bfl->fl_block)
-			p = lock_get_status(bfl->fl_block, p, i, " ->");
+		if ((bfl = fl->fl_nextblock) == NULL)
+			continue;
+		do {
+			p = lock_get_status(bfl, p, i, " ->");
+		} while ((bfl = bfl->fl_nextblock) != fl);
 	}
 	return  (p - buf);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/minix/dir.c linux/fs/minix/dir.c
--- lx2.0/v2.0.21/linux/fs/minix/dir.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/minix/dir.c	Sat Sep 28 23:23:42 1996
@@ -14,7 +14,8 @@
 
 #include <asm/segment.h>
 
-static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long minix_dir_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/minix/file.c linux/fs/minix/file.c
--- lx2.0/v2.0.21/linux/fs/minix/file.c	Tue Feb 20 10:28:13 1996
+++ linux/fs/minix/file.c	Sat Sep 28 23:22:55 1996
@@ -27,7 +27,7 @@
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
 
-static int minix_file_write(struct inode *, struct file *, const char *, int);
+static long minix_file_write(struct inode *, struct file *, const char *, unsigned long);
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -66,7 +66,8 @@
 	NULL			/* permission */
 };
 
-static int minix_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long minix_file_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	off_t pos;
 	int written,c;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- lx2.0/v2.0.21/linux/fs/ncpfs/dir.c	Wed Sep 11 17:57:15 1996
+++ linux/fs/ncpfs/dir.c	Thu Sep 26 15:28:30 1996
@@ -10,6 +10,7 @@
 #include <linux/stat.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/ncp_fs.h>
 #include <asm/segment.h>
@@ -1228,13 +1229,15 @@
 static int
 utc2local(int time)
 {
-        return time - sys_tz.tz_minuteswest*60;
+        return time - sys_tz.tz_minuteswest*60 +
+	    (sys_tz.tz_dsttime ? 3600 : 0);
 }
 
 static int
 local2utc(int time)
 {
-        return time + sys_tz.tz_minuteswest*60;
+        return time + sys_tz.tz_minuteswest*60 -
+	    (sys_tz.tz_dsttime ? 3600 : 0);
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- lx2.0/v2.0.21/linux/fs/nfs/dir.c	Sat Jul 20 09:25:25 1996
+++ linux/fs/nfs/dir.c	Sat Sep 28 23:42:49 1996
@@ -21,7 +21,7 @@
 #include <asm/segment.h>	/* for fs functions */
 
 static int nfs_dir_open(struct inode * inode, struct file * file);
-static int nfs_dir_read(struct inode *, struct file *, char *, int);
+static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
 static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
 static int nfs_lookup(struct inode *, const char *, int, struct inode **);
 static int nfs_create(struct inode *, const char *, int, int, struct inode **);
@@ -93,8 +93,8 @@
 	return 0;
 }
 
-static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf,
-			int count)
+static long nfs_dir_read(struct inode *inode, struct file *filp,
+	char *buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- lx2.0/v2.0.21/linux/fs/nfs/file.c	Sat Jul 20 08:56:29 1996
+++ linux/fs/nfs/file.c	Sat Sep 28 23:26:24 1996
@@ -30,8 +30,8 @@
 #include <asm/system.h>
 
 static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
-static int nfs_file_read(struct inode *, struct file *, char *, int);
-static int nfs_file_write(struct inode *, struct file *, const char *, int);
+static long nfs_file_read(struct inode *, struct file *, char *, unsigned long);
+static long nfs_file_write(struct inode *, struct file *, const char *, unsigned long);
 static int nfs_fsync(struct inode *, struct file *);
 
 static struct file_operations nfs_file_operations = {
@@ -87,8 +87,8 @@
 }
 
 
-static int nfs_file_read(struct inode * inode, struct file * file,
-	char * buf, int count)
+static long nfs_file_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	revalidate_inode(NFS_SERVER(inode), inode);
 	return generic_file_read(inode, file, buf, count);
@@ -105,8 +105,8 @@
 	return 0;
 }
 
-static int nfs_file_write(struct inode *inode, struct file *file, const char *buf,
-			  int count)
+static long nfs_file_write(struct inode *inode, struct file *file,
+	const char *buf, unsigned long count)
 {
 	int result, written, wsize;
 	struct nfs_fattr fattr;
@@ -121,7 +121,7 @@
 			inode->i_mode);
 		return -EINVAL;
 	}
-	if (count <= 0)
+	if (count == 0)
 		return 0;
 
 	pos = file->f_pos;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/pipe.c linux/fs/pipe.c
--- lx2.0/v2.0.21/linux/fs/pipe.c	Sun Jul  7 20:27:04 1996
+++ linux/fs/pipe.c	Sat Sep 28 23:52:55 1996
@@ -27,7 +27,8 @@
 /* in case of paging and multiple read/write on the same pipe. (FGC)         */
 
 
-static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long pipe_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	int chars = 0, size = 0, read = 0;
         char *pipebuf;
@@ -76,7 +77,8 @@
 	return 0;
 }
 	
-static int pipe_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long pipe_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	int chars = 0, free = 0, written = 0;
 	char *pipebuf;
@@ -124,17 +126,20 @@
 	return written;
 }
 
-static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+static long long pipe_lseek(struct inode * inode, struct file * file,
+	long long offset, int orig)
 {
 	return -ESPIPE;
 }
 
-static int bad_pipe_r(struct inode * inode, struct file * filp, char * buf, int count)
+static long bad_pipe_r(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	return -EBADF;
 }
 
-static int bad_pipe_w(struct inode * inode, struct file * filp, const char * buf, int count)
+static long bad_pipe_w(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	return -EBADF;
 }
@@ -214,7 +219,8 @@
  * the open() code hasn't guaranteed a connection (O_NONBLOCK),
  * and we need to act differently until we do get a writer..
  */
-static int connect_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long connect_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
 		return 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/proc/array.c linux/fs/proc/array.c
--- lx2.0/v2.0.21/linux/fs/proc/array.c	Thu Aug 29 19:15:14 1996
+++ linux/fs/proc/array.c	Sat Sep 28 23:31:52 1996
@@ -59,7 +59,8 @@
 #endif
 
 
-static int read_core(struct inode * inode, struct file * file,char * buf, int count)
+static long read_core(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	unsigned long p = file->f_pos, memsize;
 	int read;
@@ -74,14 +75,12 @@
 
 	memset(&dump, 0, sizeof(struct user));
 	dump.magic = CMAGIC;
-	dump.u_dsize = MAP_NR(high_memory);
+	dump.u_dsize = max_mapnr;
 #ifdef __alpha__
 	dump.start_data = PAGE_OFFSET;
 #endif
 
-	if (count < 0)
-		return -EINVAL;
-	memsize = MAP_NR(high_memory + PAGE_SIZE) << PAGE_SHIFT;
+	memsize = (max_mapnr + 1) << PAGE_SHIFT;
 	if (p >= memsize)
 		return 0;
 	if (count > memsize - p)
@@ -129,15 +128,14 @@
  * buffer. Use of the program readprofile is recommended in order to
  * get meaningful info out of these data.
  */
-static int read_profile(struct inode *inode, struct file *file, char *buf, int count)
+static long read_profile(struct inode *inode, struct file *file,
+	char *buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
 	int read;
 	char * pnt;
 	unsigned int sample_step = 1 << prof_shift;
 
-	if (count < 0)
-		return -EINVAL;
 	if (p >= (prof_len+1)*sizeof(unsigned int))
 		return 0;
 	if (count > (prof_len+1)*sizeof(unsigned int) - p)
@@ -156,7 +154,8 @@
 }
 
 /* Writing to /proc/profile resets the counters */
-static int write_profile(struct inode * inode, struct file * file, const char * buf, int count)
+static long write_profile(struct inode * inode, struct file * file,
+	const char * buf, unsigned long count)
 {
     int i=prof_len;
 
@@ -762,7 +761,7 @@
 		++*pages;
 		if (pte_dirty(page))
 			++*dirty;
-		if (pte_page(page) >= high_memory)
+		if (MAP_NR(pte_page(page)) >= max_mapnr)
 			continue;
 		if (mem_map[MAP_NR(pte_page(page))].count > 1)
 			++*shared;
@@ -871,7 +870,8 @@
 #define MAPS_LINE_MAX	MAPS_LINE_MAX8
 
 
-static int read_maps (int pid, struct file * file, char * buf, int count)
+static long read_maps (int pid, struct file * file,
+	char * buf, unsigned long count)
 {
 	struct task_struct ** p = get_task(pid);
 	char * destptr;
@@ -980,7 +980,8 @@
 extern int get_smp_prof_list(char *);
 #endif
 
-static int get_root_array(char * page, int type, char **start, off_t offset, int length)
+static long get_root_array(char * page, int type, char **start,
+	off_t offset, unsigned long length)
 {
 	switch (type) {
 		case PROC_LOADAVG:
@@ -1083,7 +1084,8 @@
 
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
-static int array_read(struct inode * inode, struct file * file,char * buf, int count)
+static long array_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	unsigned long page;
 	char *start;
@@ -1092,8 +1094,6 @@
 	unsigned int type, pid;
 	struct proc_dir_entry *dp;
 
-	if (count < 0)
-		return -EINVAL;
 	if (count > PROC_BLOCK_SIZE)
 		count = PROC_BLOCK_SIZE;
 	if (!(page = __get_free_page(GFP_KERNEL)))
@@ -1167,13 +1167,11 @@
 	NULL			/* permission */
 };
 
-static int arraylong_read (struct inode * inode, struct file * file, char * buf, int count)
+static long arraylong_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	unsigned int pid = inode->i_ino >> 16;
 	unsigned int type = inode->i_ino & 0x0000ffff;
-
-	if (count < 0)
-		return -EINVAL;
 
 	switch (type) {
 		case PROC_PID_MAPS:
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c
--- lx2.0/v2.0.21/linux/fs/proc/kmsg.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/proc/kmsg.c	Sat Sep 28 23:32:52 1996
@@ -28,7 +28,8 @@
 	(void) sys_syslog(0,NULL,0);
 }
 
-static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count)
+static long kmsg_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	return sys_syslog(2,buf,count);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- lx2.0/v2.0.21/linux/fs/proc/mem.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/proc/mem.c	Sat Sep 28 23:27:46 1996
@@ -76,7 +76,8 @@
 	return tsk;
 }
 
-static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
+static long mem_read(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	pgd_t *page_dir;
 	pmd_t *page_middle;
@@ -87,8 +88,6 @@
 	char *tmp;
 	int i;
 
-	if (count < 0)
-		return -EINVAL;
 	tsk = get_task(inode->i_ino >> 16);
 	if (!tsk)
 		return -ESRCH;
@@ -134,7 +133,8 @@
 
 #ifndef mem_write
 
-static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
+static long mem_write(struct inode * inode, struct file * file,
+	char * buf, unsigned long count)
 {
 	pgd_t *page_dir;
 	pmd_t *page_middle;
@@ -145,8 +145,6 @@
 	char *tmp;
 	int i;
 
-	if (count < 0)
-		return -EINVAL;
 	addr = file->f_pos;
 	tsk = get_task(inode->i_ino >> 16);
 	if (!tsk)
@@ -195,7 +193,8 @@
 
 #endif
 
-static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+static long long mem_lseek(struct inode * inode, struct file * file,
+	long long offset, int orig)
 {
 	switch (orig) {
 		case 0:
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/proc/net.c linux/fs/proc/net.c
--- lx2.0/v2.0.21/linux/fs/proc/net.c	Sun Jan 14 16:47:28 1996
+++ linux/fs/proc/net.c	Sat Sep 28 23:32:17 1996
@@ -35,8 +35,8 @@
 
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
-static int proc_readnet(struct inode * inode, struct file * file,
-			char * buf, int count)
+static long proc_readnet(struct inode * inode, struct file * file,
+			char * buf, unsigned long count)
 {
 	char * page;
 	int bytes=count;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- lx2.0/v2.0.21/linux/fs/proc/scsi.c	Fri Apr 12 09:49:44 1996
+++ linux/fs/proc/scsi.c	Sat Sep 28 23:37:07 1996
@@ -29,11 +29,11 @@
 #include <asm/segment.h>
 
 /* forward references */
-static int proc_readscsi(struct inode * inode, struct file * file,
-			 char * buf, int count);
-static int proc_writescsi(struct inode * inode, struct file * file,
-			 const char * buf, int count);
-static int proc_scsilseek(struct inode *, struct file *, off_t, int);
+static long proc_readscsi(struct inode * inode, struct file * file,
+			 char * buf, unsigned long count);
+static long proc_writescsi(struct inode * inode, struct file * file,
+			 const char * buf, unsigned long count);
+static long long proc_scsilseek(struct inode *, struct file *, long long, int);
 
 extern void build_proc_dir_hba_entries(uint);
 
@@ -101,8 +101,8 @@
 				      * use some slack for overruns 
 				      */
 
-static int proc_readscsi(struct inode * inode, struct file * file,
-			 char * buf, int count)
+static long proc_readscsi(struct inode * inode, struct file * file,
+			  char * buf, unsigned long count)
 {
     int length;
     int bytes = count;
@@ -111,16 +111,12 @@
     char * page;
     char * start;
     
-    if (count < -1)		  /* Normally I wouldn't do this, */ 
-	return(-EINVAL);	  /* but it saves some redundant code.
-				   * Now it is possible to seek to the 
-				   * end of the file */
     if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 	return(-ENOMEM);
     
-    while(bytes > 0 || count == -1) {	
+    while (bytes > 0) {	
 	thistime = bytes;
-	if(bytes > PROC_BLOCK_SIZE || count == -1)
+	if(bytes > PROC_BLOCK_SIZE)
 	    thistime = PROC_BLOCK_SIZE;
 	
 	if(dispatch_scsi_info_ptr)
@@ -141,11 +137,9 @@
 	if (length <= 0)
 	    break;
 	/*
-	 *  Copy the bytes, if we're not doing a seek to 
-	 *	the end of the file 
+	 *  Copy the bytes
 	 */
-	if (count != -1)
-	    memcpy_tofs(buf + copied, start, length);
+	memcpy_tofs(buf + copied, start, length);
 	file->f_pos += length;	/* Move down the file */
 	bytes -= length;
 	copied += length;
@@ -160,8 +154,8 @@
 }
 
 
-static int proc_writescsi(struct inode * inode, struct file * file,
-			 const char * buf, int count)
+static long proc_writescsi(struct inode * inode, struct file * file,
+			   const char * buf, unsigned long count)
 {
     int ret = 0;
     char * page;
@@ -183,8 +177,8 @@
 }
 
 
-static int proc_scsilseek(struct inode * inode, struct file * file, 
-			  off_t offset, int orig)
+static long long proc_scsilseek(struct inode * inode, struct file * file, 
+				long long offset, int orig)
 {
     switch (orig) {
     case 0:
@@ -193,11 +187,8 @@
     case 1:
 	file->f_pos += offset;
 	return(file->f_pos);
-    case 2:		     /* This ugly hack allows us to    */
-	if (offset)	     /* to determine the length of the */
-	    return(-EINVAL); /* file and then later safely to  */ 
-	proc_readscsi(inode, file, 0, -1); /* seek in it       */ 
-	return(file->f_pos);
+    case 2:
+	return(-EINVAL);
     default:
 	return(-EINVAL);
     }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/read_write.c linux/fs/read_write.c
--- lx2.0/v2.0.21/linux/fs/read_write.c	Wed Aug 21 09:18:09 1996
+++ linux/fs/read_write.c	Sat Sep 28 23:48:01 1996
@@ -25,8 +25,8 @@
 		return -EBADF;
 	if (origin > 2)
 		return -EINVAL;
-	if (file->f_op && file->f_op->lseek)
-		return file->f_op->lseek(file->f_inode,file,offset,origin);
+	if (file->f_op && file->f_op->llseek)
+		return file->f_op->llseek(file->f_inode,file,offset,origin);
 
 /* this is the default handler if no lseek handler is present */
 	switch (origin) {
@@ -69,13 +69,8 @@
 		return err;
 	offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
 
-	/* if there is a fs-specific handler, we can't just ignore it.. */
-	/* accept llseek() only for the signed long subset of long long */
-	if (file->f_op && file->f_op->lseek) {
-		if (offset != (long) offset)
-			return -EINVAL;
-		return file->f_op->lseek(file->f_inode,file,offset,origin);
-	}
+	if (file->f_op && file->f_op->llseek)
+		return file->f_op->llseek(file->f_inode,file,offset,origin);
 
 	switch (origin) {
 		case 0:
@@ -101,7 +96,7 @@
 	return 0;
 }
 
-asmlinkage int sys_read(unsigned int fd,char * buf,int count)
+asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
 {
 	int error;
 	struct file * file;
@@ -136,7 +131,7 @@
 	return error;
 }
 
-asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
+asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count)
 {
 	int error;
 	struct file * file;
@@ -191,7 +186,7 @@
 	return error;
 }
 
-static int sock_readv_writev(int type, struct inode * inode, struct file * file,
+static long sock_readv_writev(int type, struct inode * inode, struct file * file,
 	const struct iovec * iov, long count, long size)
 {
 	struct msghdr msg;
@@ -219,14 +214,14 @@
 		(file->f_flags & O_NONBLOCK), 0);
 }
 
-typedef int (*IO_fn_t)(struct inode *, struct file *, char *, int);
+typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
 
-static int do_readv_writev(int type, struct inode * inode, struct file * file,
+static long do_readv_writev(int type, struct inode * inode, struct file * file,
 	const struct iovec * vector, unsigned long count)
 {
-	size_t tot_len;
+	unsigned long tot_len;
 	struct iovec iov[UIO_MAXIOV];
-	int retval, i;
+	long retval, i;
 	IO_fn_t fn;
 
 	/*
@@ -291,7 +286,7 @@
 	return retval;
 }
 
-asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count)
+asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
 {
 	struct file * file;
 	struct inode * inode;
@@ -303,7 +298,7 @@
 	return do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
 }
 
-asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count)
+asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
 {
 	int error;
 	struct file * file;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- lx2.0/v2.0.21/linux/fs/smbfs/dir.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/dir.c	Mon Sep 30 11:13:36 1996
@@ -18,8 +18,8 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+3) & ~3)
 
-static int 
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
+static long
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count);
 
 static int 
 smb_readdir(struct inode *inode, struct file *filp,
@@ -115,8 +115,8 @@
 };
 
 
-static int 
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
+static long
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- lx2.0/v2.0.21/linux/fs/smbfs/file.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/file.c	Mon Sep 30 11:13:09 1996
@@ -63,8 +63,8 @@
         return -EACCES;
 }
 
-static int 
-smb_file_read(struct inode *inode, struct file *file, char *buf, int count)
+static long
+smb_file_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
 {
 	int result, bufsize, to_read, already_read;
 	off_t pos;
@@ -140,9 +140,9 @@
         return already_read;
 }
 
-static int 
+static long
 smb_file_write(struct inode *inode, struct file *file, const char *buf,
-	       int count)
+	       unsigned long count)
 {
 	int result, bufsize, to_write, already_written;
         off_t pos;
@@ -161,7 +161,7 @@
 
         DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->path);
 
-	if (count <= 0)
+	if (!count)
 		return 0;
 
         if ((errno = smb_make_open(inode, O_RDWR)) != 0)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- lx2.0/v2.0.21/linux/fs/smbfs/proc.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/smbfs/proc.c	Thu Sep 26 15:28:30 1996
@@ -170,13 +170,15 @@
 static int
 utc2local(int time)
 {
-        return time - sys_tz.tz_minuteswest*60;
+        return time - sys_tz.tz_minuteswest*60 +
+	    (sys_tz.tz_dsttime ? 3600 : 0);
 }
 
 static int
 local2utc(int time)
 {
-        return time + sys_tz.tz_minuteswest*60;
+        return time + sys_tz.tz_minuteswest*60 -
+	    (sys_tz.tz_dsttime ? 3600 : 0);
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- lx2.0/v2.0.21/linux/fs/sysv/dir.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/sysv/dir.c	Mon Sep 30 11:11:25 1996
@@ -21,7 +21,8 @@
 
 #include <asm/segment.h>
 
-static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long sysv_dir_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- lx2.0/v2.0.21/linux/fs/sysv/file.c	Mon May  6 12:26:15 1996
+++ linux/fs/sysv/file.c	Mon Sep 30 11:10:36 1996
@@ -33,7 +33,7 @@
 #include <linux/fs.h>
 #include <linux/sysv_fs.h>
 
-static int sysv_file_write(struct inode *, struct file *, const char *, int);
+static long sysv_file_write(struct inode *, struct file *, const char *, unsigned long);
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -72,7 +72,8 @@
 	NULL			/* permission */
 };
 
-int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+long sysv_file_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	struct super_block * sb = inode->i_sb;
 	int read,left,chars;
@@ -199,7 +200,8 @@
 	return read;
 }
 
-static int sysv_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long sysv_file_write(struct inode * inode, struct file * filp,
+	const char * buf, unsigned long count)
 {
 	struct super_block * sb = inode->i_sb;
 	off_t pos;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- lx2.0/v2.0.21/linux/fs/umsdos/dir.c	Fri Apr 12 09:49:44 1996
+++ linux/fs/umsdos/dir.c	Mon Sep 30 11:05:34 1996
@@ -27,8 +27,8 @@
 /*
 	So  grep *  doesn't complain in the presence of directories.
 */
-int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
-    int count)
+long UMSDOS_dir_read(struct inode *inode,struct file *filp,
+	char *buf, unsigned long count)
 {
 	return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- lx2.0/v2.0.21/linux/fs/umsdos/file.c	Tue Feb 20 10:28:13 1996
+++ linux/fs/umsdos/file.c	Mon Sep 30 11:06:07 1996
@@ -24,11 +24,11 @@
 /*
 	Read a file into user space memory
 */
-static int UMSDOS_file_read(
+static long UMSDOS_file_read(
 	struct inode *inode,
 	struct file *filp,
 	char *buf,
-    int count)
+	unsigned long count)
 {
 	/* We have to set the access time because msdos don't care */
 	int ret = fat_file_read(inode,filp,buf,count);
@@ -41,11 +41,11 @@
 /*
 	Write a file from user space memory
 */
-static int UMSDOS_file_write(
+static long UMSDOS_file_write(
 	struct inode *inode,
 	struct file *filp,
 	const char *buf,
-    int count)
+	unsigned long count)
 {
 	return fat_file_write(inode,filp,buf,count);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- lx2.0/v2.0.21/linux/fs/umsdos/symlink.c	Wed Feb  7 09:39:29 1996
+++ linux/fs/umsdos/symlink.c	Mon Sep 30 11:07:22 1996
@@ -29,7 +29,7 @@
 static int umsdos_readlink_x (
 	struct inode *inode,
 	char *buffer,
-	int (*msdos_read)(struct inode *, struct file *, char *, int),
+	long (*msdos_read)(struct inode *, struct file *, char *, unsigned long),
 	int bufsiz)
 {
 	int ret = inode->i_size;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/xiafs/dir.c linux/fs/xiafs/dir.c
--- lx2.0/v2.0.21/linux/fs/xiafs/dir.c	Fri Dec 22 13:00:19 1995
+++ linux/fs/xiafs/dir.c	Mon Sep 30 11:04:58 1996
@@ -20,7 +20,7 @@
 
 #include "xiafs_mac.h"
 
-static int xiafs_dir_read(struct inode *, struct file *, char *, int);
+static long xiafs_dir_read(struct inode *, struct file *, char *, unsigned long);
 static int xiafs_readdir(struct inode *, struct file *, void *, filldir_t);
 
 static struct file_operations xiafs_dir_operations = {
@@ -59,8 +59,8 @@
     NULL			/* permission */
 };
 
-static int xiafs_dir_read(struct inode * inode, 
-			struct file * filp, char * buf, int count)
+static long xiafs_dir_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
   return -EISDIR;
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/fs/xiafs/file.c linux/fs/xiafs/file.c
--- lx2.0/v2.0.21/linux/fs/xiafs/file.c	Mon May  6 12:26:15 1996
+++ linux/fs/xiafs/file.c	Mon Sep 30 11:04:19 1996
@@ -29,8 +29,8 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-static int xiafs_file_read(struct inode *, struct file *, char *, int);
-static int xiafs_file_write(struct inode *, struct file *, const char *, int);
+static long xiafs_file_read(struct inode *, struct file *, char *, unsigned long);
+static long xiafs_file_write(struct inode *, struct file *, const char *, unsigned long);
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -69,8 +69,8 @@
     NULL			/* permission */
 };
 
-static int 
-xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+static long
+xiafs_file_read(struct inode * inode, struct file * filp, char * buf, unsigned long count)
 {
     int read, left, chars;
     int zone_nr, zones, f_zones, offset;
@@ -189,8 +189,8 @@
     return read;
 }
 
-static int 
-xiafs_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
+static long
+xiafs_file_write(struct inode * inode, struct file * filp, const char * buf, unsigned long count)
 {
     off_t pos;
     int written, c;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/fcntl.h	Mon Aug  5 10:13:54 1996
+++ linux/include/asm-alpha/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -49,12 +49,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/floppy.h linux/include/asm-alpha/floppy.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/floppy.h	Sat Mar 30 11:48:51 1996
+++ linux/include/asm-alpha/floppy.h	Sat Sep 28 22:05:41 1996
@@ -21,7 +21,7 @@
 #define fd_free_dma()           free_dma(FLOPPY_DMA)
 #define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
 #define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
-#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,addr)
+#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,virt_to_bus(addr))
 #define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/io.h	Tue Jun  4 06:06:38 1996
+++ linux/include/asm-alpha/io.h	Mon Sep 30 16:52:20 1996
@@ -152,7 +152,19 @@
 /*
  * The "address" in IO memory space is not clearly either a integer or a
  * pointer. We will accept both, thus the casts.
+ *
+ * On the alpha, we have the whole physical address space mapped at all
+ * times, so "ioremap()" and "iounmap()" do not need to do anything.
  */
+extern inline void * ioremap(unsigned long offset, unsigned long size)
+{
+	return (void *) offset;
+} 
+
+extern inline void iounmap(void *addr)
+{
+}
+
 #ifndef readb
 # define readb(a)	_readb((unsigned long)(a))
 #endif
@@ -202,6 +214,22 @@
  */
 
 #define eth_io_copy_and_sum(skb,src,len,unused)	memcpy_fromio((skb)->data,(src),(len))
+
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/page.h	Mon Jan  8 08:14:54 1996
+++ linux/include/asm-alpha/page.h	Wed Sep 25 12:25:44 1996
@@ -52,7 +52,9 @@
 #define PAGE_ALIGN(addr)		(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 #define PAGE_OFFSET		0xFFFFFC0000000000UL
-#define MAP_NR(addr)		((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
+#define __pa(x)			((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/pgtable.h	Fri Apr 19 13:38:28 1996
+++ linux/include/asm-alpha/pgtable.h	Wed Sep 25 14:33:57 1996
@@ -266,8 +266,6 @@
 #define PAGE_PTR(address)		\
   ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
-extern unsigned long high_memory;
-
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -275,6 +273,9 @@
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
 { pte_t pte; pte_val(pte) = ((page-PAGE_OFFSET) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
 
+extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = (physpage << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
+
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
@@ -298,12 +299,12 @@
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE; }
 extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
 
 extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE; }
 extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
 extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-alpha/segment.h linux/include/asm-alpha/segment.h
--- lx2.0/v2.0.21/linux/include/asm-alpha/segment.h	Wed Aug 21 09:18:09 1996
+++ linux/include/asm-alpha/segment.h	Mon Sep 23 17:44:17 1996
@@ -4,79 +4,21 @@
 #include <linux/string.h>
 
 /*
- * This is a gcc optimization barrier, which essentially
- * inserts a sequence point in the gcc RTL tree that gcc
- * can't move code around. This is needed when we enter
- * or exit a critical region (in this case around user-level
- * accesses that may sleep, and we can't let gcc optimize
- * global state around them).
- */
-#define __gcc_barrier() __asm__ __volatile__("": : :"memory")
-
-/*
  * Uh, these should become the main single-value transfer routines..
  * They automatically use the right size if we just have the right
  * pointer type..
+ *
+ * As the alpha uses the same address space for kernel and user
+ * data, we can just do these as direct assignments.
  */
-#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
+#define put_user(x,ptr)	do { (*(ptr)=(x)); } while (0)
+#define get_user(ptr)	(*(ptr))
 
 /*
- * This is a silly but good way to make sure that
- * the __put_user function is indeed always optimized,
- * and that we use the correct sizes..
+ * These are deprecated..
+ *
+ * Use "put_user()" and "get_user()" with the proper pointer types instead.
  */
-extern int bad_user_access_length(void);
-
-/* I should make this use unaligned transfers etc.. */
-static inline void __put_user(unsigned long x, void * y, int size)
-{
-	__gcc_barrier();
-	switch (size) {
-		case 1:
-			*(char *) y = x;
-			break;
-		case 2:
-			*(short *) y = x;
-			break;
-		case 4:
-			*(int *) y = x;
-			break;
-		case 8:
-			*(long *) y = x;
-			break;
-		default:
-			bad_user_access_length();
-	}
-	__gcc_barrier();
-}
-
-/* I should make this use unaligned transfers etc.. */
-static inline unsigned long __get_user(const void * y, int size)
-{
-	unsigned long result;
-
-	__gcc_barrier();
-	switch (size) {
-		case 1:
-			result = *(unsigned char *) y;
-			break;
-		case 2:
-			result = *(unsigned short *) y;
-			break;
-		case 4:
-			result = *(unsigned int *) y;
-			break;
-		case 8:
-			result = *(unsigned long *) y;
-			break;
-		default:
-			result = bad_user_access_length();
-	}
-	__gcc_barrier();
-	return result;
-}
-
 #define get_fs_byte(addr) get_user((unsigned char *)(addr))
 #define get_fs_word(addr) get_user((unsigned short *)(addr))
 #define get_fs_long(addr) get_user((unsigned int *)(addr))
@@ -87,19 +29,8 @@
 #define put_fs_long(x,addr) put_user((x),(int *)(addr))
 #define put_fs_quad(x,addr) put_user((x),(long *)(addr))
 
-static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
-{
-	__gcc_barrier();
-	memcpy(to, from, n);
-	__gcc_barrier();
-}
-
-static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
-{
-	__gcc_barrier();
-	memcpy(to, from, n);
-	__gcc_barrier();
-}
+#define memcpy_fromfs(to,from,n) memcpy((to),(from),(n))
+#define memcpy_tofs(to,from,n) memcpy((to),(from),(n))
 
 /*
  * The fs value determines whether argument validity checking should be
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- lx2.0/v2.0.21/linux/include/asm-i386/checksum.h	Tue May 28 12:27:59 1996
+++ linux/include/asm-i386/checksum.h	Mon Sep 23 15:32:35 1996
@@ -27,13 +27,10 @@
 
 
 /*
- * the same as csum_partial_copy, but copies from user space.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
+ * the same as csum_partial, but copies from user space (but on the x86
+ * we have just one address space, so this is identical to the above)
  */
-
-unsigned int csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum);
+#define csum_partial_copy_fromuser csum_partial_copy
 
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/dma.h linux/include/asm-i386/dma.h
--- lx2.0/v2.0.21/linux/include/asm-i386/dma.h	Tue Aug  1 10:02:44 1995
+++ linux/include/asm-i386/dma.h	Sat Sep 28 23:01:29 1996
@@ -70,7 +70,7 @@
 #define MAX_DMA_CHANNELS	8
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS      0x1000000
+#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-i386/fcntl.h	Wed Jul 17 15:10:03 1996
+++ linux/include/asm-i386/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -48,12 +48,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/floppy.h linux/include/asm-i386/floppy.h
--- lx2.0/v2.0.21/linux/include/asm-i386/floppy.h	Sun Apr 28 18:47:40 1996
+++ linux/include/asm-i386/floppy.h	Mon Sep 30 11:19:53 1996
@@ -10,6 +10,7 @@
 #ifndef __ASM_I386_FLOPPY_H
 #define __ASM_I386_FLOPPY_H
 
+#include <linux/vmalloc.h>
 
 #define SW fd_routine[use_virtual_dma&1]
 
@@ -38,7 +39,7 @@
 
 static int virtual_dma_count=0;
 static int virtual_dma_residue=0;
-static unsigned long virtual_dma_addr=0;
+static char *virtual_dma_addr=0;
 static int virtual_dma_mode=0;
 static int doing_pdma=0;
 
@@ -101,7 +102,7 @@
 		register char *lptr;
 
 		st = 1;
-		for(lcount=virtual_dma_count, lptr=(char *)virtual_dma_addr; 
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
 		    lcount; lcount--, lptr++) {
 			st=inb(virtual_dma_port+4) & 0xa0 ;
 			if(st != 0xa0) 
@@ -113,7 +114,7 @@
 			st = inb(virtual_dma_port+4);
 		}
 		virtual_dma_count = lcount;
-		virtual_dma_addr = (int) lptr;
+		virtual_dma_addr = lptr;
 	}
 #endif
 
@@ -168,7 +169,12 @@
 	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
 }
 
-static void vdma_set_dma_addr(unsigned int dummy,unsigned int addr)
+static void hset_dma_addr(unsigned int no, char *addr)
+{
+	set_dma_addr(no, virt_to_bus(addr));
+}
+
+static void vdma_set_dma_addr(unsigned int dummy, char *addr)
 {
 	virtual_dma_addr = addr;
 }
@@ -222,7 +228,7 @@
 	void (*_free_dma)(unsigned int dmanr);
 	void (*_clear_dma_ff)(unsigned int dummy);
 	void (*_set_dma_mode)(unsigned int dummy, char mode);
-	void (*_set_dma_addr)(unsigned int dummy, unsigned int addr);
+	void (*_set_dma_addr)(unsigned int dummy, char *addr);
 	void (*_set_dma_count)(unsigned int dummy, unsigned int count);
 	int (*_get_dma_residue)(unsigned int dummy);
 	int (*_request_irq)(unsigned int irq,
@@ -240,7 +246,7 @@
 		free_dma,
 		clear_dma_ff,
 		set_dma_mode,
-		set_dma_addr,
+		hset_dma_addr,
 		set_dma_count,
 		get_dma_residue,
 		request_irq,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- lx2.0/v2.0.21/linux/include/asm-i386/io.h	Sun Oct  1 19:18:58 1995
+++ linux/include/asm-i386/io.h	Mon Sep 30 16:52:08 1996
@@ -37,22 +37,27 @@
 #define SLOW_DOWN_IO __SLOW_DOWN_IO
 #endif
 
+#include <asm/page.h>
+
+#define __io_virt(x)		((void *)(PAGE_OFFSET | (unsigned long)(x)))
+#define __io_phys(x)		((unsigned long)(x) & ~PAGE_OFFSET)
 /*
  * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
+ * These are pretty trivial
  */
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
-	return (unsigned long) address;
+	return __io_phys(address);
 }
 
 extern inline void * phys_to_virt(unsigned long address)
 {
-	return (void *) address;
+	return __io_virt(address);
 }
 
+extern void * ioremap(unsigned long offset, unsigned long size);
+extern void iounmap(void *addr);
+
 /*
  * IO bus memory addresses are also 1:1 with the physical address
  */
@@ -65,23 +70,24 @@
  * differently. On the x86 architecture, we just read/write the
  * memory location directly.
  */
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
-
-#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
+#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
+#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+
+#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+
+#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
 
 /*
  * Again, i386 does not require mem IO specific function.
  */
 
-#define eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),(void *)(b),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(b),(c),(d))
 
 /*
  * Talk about misusing macros..
@@ -209,5 +215,21 @@
 ((__builtin_constant_p((port)) && (port) < 256) ? \
 	__inlc_p(port) : \
 	__inl_p(port))
+
+static inline int check_signature(unsigned long io_addr,
+	const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
 
 #endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- lx2.0/v2.0.21/linux/include/asm-i386/irq.h	Wed Sep 11 17:57:17 1996
+++ linux/include/asm-i386/irq.h	Tue Sep 24 12:20:49 1996
@@ -21,7 +21,10 @@
 
 #define __STR(x) #x
 #define STR(x) __STR(x)
- 
+
+#define GET_CURRENT \
+	"movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
+
 #define SAVE_ALL \
 	"cld\n\t" \
 	"push %gs\n\t" \
@@ -38,8 +41,6 @@
 	"movl $" STR(KERNEL_DS) ",%edx\n\t" \
 	"mov %dx,%ds\n\t" \
 	"mov %dx,%es\n\t" \
-	"movl $" STR(USER_DS) ",%edx\n\t" \
-	"mov %dx,%fs\n\t"   \
 	"movl $0,%edx\n\t"  \
 	"movl %edx,%db7\n\t"
 
@@ -143,7 +144,10 @@
 	"movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
 	"movl 32(%edx), %eax\n\t" \
 	"shrl $24,%eax\n\t" \
-	"andb $0x0F,%al\n"
+	"andb $0x0F,%al\n\t"
+
+#define GET_CURRENT \
+	"movl " SYMBOL_NAME_STR(current_set) "(,%eax,4),%ebx\n\t"
 	
 #define	ENTER_KERNEL \
 	"pushl %eax\n\t" \
@@ -151,6 +155,7 @@
 	"pushfl\n\t" \
 	"cli\n\t" \
 	GET_PROCESSOR_ID \
+	GET_CURRENT \
 	"btsl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 	"1: " \
 	"lock\n\t" \
@@ -210,8 +215,8 @@
 	ACK_##chip(mask,(nr&7)) \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"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" \
@@ -257,8 +262,8 @@
 	ENTER_KERNEL \
 	ACK_##chip(mask,(nr&7)) \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"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" \
@@ -286,8 +291,8 @@
 	ACK_##chip(mask,(nr&7)) \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"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" \
@@ -325,8 +330,8 @@
 	ENTER_KERNEL \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"movl %esp,%eax\n\t" \
+	"pushl %eax\n\t" \
 	"pushl $" #nr "\n\t" \
 	"call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \
 	"addl $8,%esp\n\t" \
@@ -348,14 +353,15 @@
 	ACK_##chip(mask,(nr&7)) \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 	"sti\n\t" \
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"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" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
 	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
+	GET_CURRENT \
 	"jmp ret_from_sys_call\n" \
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
@@ -388,14 +394,15 @@
 	SAVE_ALL \
 	ACK_##chip(mask,(nr&7)) \
 	"incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
-	"movl %esp,%ebx\n\t" \
-	"pushl %ebx\n\t" \
+	"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" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
 	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
+	GET_CURRENT \
 	"jmp ret_from_sys_call\n");
 
 #endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/ldt.h linux/include/asm-i386/ldt.h
--- lx2.0/v2.0.21/linux/include/asm-i386/ldt.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/ldt.h	Tue Nov 21 08:34:54 1995
@@ -0,0 +1,29 @@
+/*
+ * ldt.h
+ *
+ * Definitions of structures used with the modify_ldt system call.
+ */
+#ifndef _LINUX_LDT_H
+#define _LINUX_LDT_H
+
+/* Maximum number of LDT entries supported. */
+#define LDT_ENTRIES	8192
+/* The size of each LDT entry. */
+#define LDT_ENTRY_SIZE	8
+
+struct modify_ldt_ldt_s {
+	unsigned int  entry_number;
+	unsigned long base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+};
+
+#define MODIFY_LDT_CONTENTS_DATA	0
+#define MODIFY_LDT_CONTENTS_STACK	1
+#define MODIFY_LDT_CONTENTS_CODE	2
+
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- lx2.0/v2.0.21/linux/include/asm-i386/page.h	Thu Nov 30 14:12:41 1995
+++ linux/include/asm-i386/page.h	Mon Sep 23 09:17:09 1996
@@ -54,8 +54,10 @@
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 /* This handles the memory map.. */
-#define PAGE_OFFSET		0
-#define MAP_NR(addr)		(((unsigned long)(addr)) >> PAGE_SHIFT)
+#define PAGE_OFFSET		0xC0000000
+#define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- lx2.0/v2.0.21/linux/include/asm-i386/pgtable.h	Sun Sep  8 19:50:21 1996
+++ linux/include/asm-i386/pgtable.h	Mon Sep 30 11:19:11 1996
@@ -197,8 +197,8 @@
  * area for the same reason. ;)
  */
 #define VMALLOC_OFFSET	(8*1024*1024)
-#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
+#define VMALLOC_START	(((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
 /*
  * The 4MB page is guessing..  Detailed in the infamous "Chapter H"
@@ -216,6 +216,7 @@
 #define _PAGE_4M	0x080	/* 4 MB page, Pentium+.. */
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
@@ -289,9 +290,10 @@
 /* to set the page-dir */
 #define SET_PAGE_DIR(tsk,pgdir) \
 do { \
-	(tsk)->tss.cr3 = (unsigned long) (pgdir); \
+	unsigned long __pgdir = __pa(pgdir); \
+	(tsk)->tss.cr3 = __pgdir; \
 	if ((tsk) == current) \
-		__asm__ __volatile__("movl %0,%%cr3": :"r" (pgdir)); \
+		__asm__ __volatile__("movl %0,%%cr3": :"r" (__pgdir)); \
 } while (0)
 
 #define pte_none(x)	(!pte_val(x))
@@ -299,7 +301,7 @@
 #define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
-#define	pmd_bad(x)	((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
+#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
 #define pmd_clear(xp)	do { pmd_val(*(xp)) = 0; } while (0)
 
@@ -338,23 +340,25 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+#define mk_pte(page, pgprot) \
+({ pte_t __pte; pte_val(__pte) = __pa(page) + pgprot_val(pgprot); __pte; })
+
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
-extern inline unsigned long pte_page(pte_t pte)
-{ return pte_val(pte) & PAGE_MASK; }
+#define pte_page(pte) \
+((unsigned long) __va(pte_val(pte) & PAGE_MASK))
 
-extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd) & PAGE_MASK; }
+#define pmd_page(pmd) \
+((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
 /* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-	return mm->pgd + (address >> PGDIR_SHIFT);
-}
+#define pgd_offset(mm, address) \
+((mm)->pgd + ((address) >> PGDIR_SHIFT))
 
 /* Find an entry in the second-level page table.. */
 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
@@ -363,10 +367,8 @@
 }
 
 /* Find an entry in the third-level page table.. */ 
-extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
+#define pte_offset(pmd, address) \
+((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
@@ -385,17 +387,17 @@
 		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
 		if (pmd_none(*pmd)) {
 			if (page) {
-				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
 				return page + address;
 			}
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
 	if (pmd_bad(*pmd)) {
 		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -439,7 +441,7 @@
 	if (!page)
 		goto oom;
 	memset((void *) page, 0, PAGE_SIZE);
-	pmd_val(*pmd) = _PAGE_TABLE | page;
+	pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
 	return (pte_t *) (page + address);
 freenew:
 	free_page(page);
@@ -449,7 +451,7 @@
 fix:
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
 oom:
-	pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
 	return NULL;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- lx2.0/v2.0.21/linux/include/asm-i386/processor.h	Sun Sep 15 10:34:18 1996
+++ linux/include/asm-i386/processor.h	Tue Sep 24 10:50:27 1996
@@ -104,7 +104,7 @@
 	unsigned short	trace, bitmap;
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
 	unsigned long	tr;
-	unsigned long	cr2, trap_no, error_code;
+	unsigned long	cr2, trap_no, error_code, segment;
 /* floating point info */
 	union i387_union i387;
 /* virtual 86 mode info */
@@ -113,20 +113,20 @@
 	unsigned long v86flags, v86mask, v86mode;
 };
 
-#define INIT_MMAP { &init_mm, 0, 0x40000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_mm, 0xC0000000, 0xFFFFF000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  { \
 	0,0, \
 	sizeof(init_kernel_stack) + (long) &init_kernel_stack, \
 	KERNEL_DS, 0, \
 	0,0,0,0,0,0, \
-	(long) &swapper_pg_dir, \
+	(long) &swapper_pg_dir - PAGE_OFFSET, \
 	0,0,0,0,0,0,0,0,0,0, \
 	USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0, \
 	_LDT(0),0, \
 	0, 0x8000, \
 	{~0, }, /* ioperm */ \
-	_TSS(0), 0, 0,0, \
+	_TSS(0), 0, 0, 0, KERNEL_DS, \
 	{ { 0, }, },  /* 387 state */ \
 	NULL, 0, 0, 0, 0 /* vm86_info */ \
 }
@@ -134,13 +134,13 @@
 #define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
 #define free_kernel_stack(page) free_page((page))
 
-static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
-{
-	regs->cs = USER_CS;
-	regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS;
-	regs->eip = eip;
-	regs->esp = esp;
-}
+#define start_thread(regs, new_eip, new_esp) do {\
+	set_fs(USER_DS); \
+	regs->cs = USER_CS; \
+	regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS; \
+	regs->eip = new_eip; \
+	regs->esp = new_esp; \
+} while (0)
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/segment.h linux/include/asm-i386/segment.h
--- lx2.0/v2.0.21/linux/include/asm-i386/segment.h	Tue Apr  9 10:35:29 1996
+++ linux/include/asm-i386/segment.h	Tue Sep 24 10:43:03 1996
@@ -9,256 +9,15 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/string.h>
+
 /*
  * Uh, these should become the main single-value transfer routines..
  * They automatically use the right size if we just have the right
  * pointer type..
  */
-#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
-
-/*
- * This is a silly but good way to make sure that
- * the __put_user function is indeed always optimized,
- * and that we use the correct sizes..
- */
-extern int bad_user_access_length(void);
-
-/*
- * dummy pointer type structure.. gcc won't try to do something strange
- * this way..
- */
-struct __segment_dummy { unsigned long a[100]; };
-#define __sd(x) ((struct __segment_dummy *) (x))
-#define __const_sd(x) ((const struct __segment_dummy *) (x))
-
-static inline void __put_user(unsigned long x, void * y, int size)
-{
-	switch (size) {
-		case 1:
-			__asm__ ("movb %b1,%%fs:%0"
-				:"=m" (*__sd(y))
-				:"iq" ((unsigned char) x), "m" (*__sd(y)));
-			break;
-		case 2:
-			__asm__ ("movw %w1,%%fs:%0"
-				:"=m" (*__sd(y))
-				:"ir" ((unsigned short) x), "m" (*__sd(y)));
-			break;
-		case 4:
-			__asm__ ("movl %1,%%fs:%0"
-				:"=m" (*__sd(y))
-				:"ir" (x), "m" (*__sd(y)));
-			break;
-		default:
-			bad_user_access_length();
-	}
-}
-
-static inline unsigned long __get_user(const void * y, int size)
-{
-	unsigned long result;
-
-	switch (size) {
-		case 1:
-			__asm__ ("movb %%fs:%1,%b0"
-				:"=q" (result)
-				:"m" (*__const_sd(y)));
-			return (unsigned char) result;
-		case 2:
-			__asm__ ("movw %%fs:%1,%w0"
-				:"=r" (result)
-				:"m" (*__const_sd(y)));
-			return (unsigned short) result;
-		case 4:
-			__asm__ ("movl %%fs:%1,%0"
-				:"=r" (result)
-				:"m" (*__const_sd(y)));
-			return result;
-		default:
-			return bad_user_access_length();
-	}
-}
-
-static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
-{
-    __asm__ volatile
-	("	cld
-		push %%es
-		push %%fs
-		cmpl $3,%0
-		pop %%es
-		jbe 1f
-		movl %%edi,%%ecx
-		negl %%ecx
-		andl $3,%%ecx
-		subl %%ecx,%0
-		rep; movsb
-		movl %0,%%ecx
-		shrl $2,%%ecx
-		rep; movsl
-		andl $3,%0
-	1:	movl %0,%%ecx
-		rep; movsb
-		pop %%es"
-	:"=abd" (n)
-	:"0" (n),"D" ((long) to),"S" ((long) from)
-	:"cx","di","si");
-}
-
-static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n)
-{
-	switch (n) {
-		case 0:
-			return;
-		case 1:
-			__put_user(*(const char *) from, (char *) to, 1);
-			return;
-		case 2:
-			__put_user(*(const short *) from, (short *) to, 2);
-			return;
-		case 3:
-			__put_user(*(const short *) from, (short *) to, 2);
-			__put_user(*(2+(const char *) from), 2+(char *) to, 1);
-			return;
-		case 4:
-			__put_user(*(const int *) from, (int *) to, 4);
-			return;
-		case 8:
-			__put_user(*(const int *) from, (int *) to, 4);
-			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
-			return;
-		case 12:
-			__put_user(*(const int *) from, (int *) to, 4);
-			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
-			__put_user(*(2+(const int *) from), 2+(int *) to, 4);
-			return;
-		case 16:
-			__put_user(*(const int *) from, (int *) to, 4);
-			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
-			__put_user(*(2+(const int *) from), 2+(int *) to, 4);
-			__put_user(*(3+(const int *) from), 3+(int *) to, 4);
-			return;
-	}
-#define COMMON(x) \
-__asm__("cld\n\t" \
-	"push %%es\n\t" \
-	"push %%fs\n\t" \
-	"pop %%es\n\t" \
-	"rep ; movsl\n\t" \
-	x \
-	"pop %%es" \
-	: /* no outputs */ \
-	:"c" (n/4),"D" ((long) to),"S" ((long) from) \
-	:"cx","di","si")
-
-	switch (n % 4) {
-		case 0:
-			COMMON("");
-			return;
-		case 1:
-			COMMON("movsb\n\t");
-			return;
-		case 2:
-			COMMON("movsw\n\t");
-			return;
-		case 3:
-			COMMON("movsw\n\tmovsb\n\t");
-			return;
-	}
-#undef COMMON
-}
-
-static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n)
-{
-    __asm__ volatile
-	("	cld
-		cmpl $3,%0
-		jbe 1f
-		movl %%edi,%%ecx
-		negl %%ecx
-		andl $3,%%ecx
-		subl %%ecx,%0
-		fs; rep; movsb
-		movl %0,%%ecx
-		shrl $2,%%ecx
-		fs; rep; movsl
-		andl $3,%0
-	1:	movl %0,%%ecx
-		fs; rep; movsb"
-	:"=abd" (n)
-	:"0" (n),"D" ((long) to),"S" ((long) from)
-	:"cx","di","si", "memory");
-}
-
-static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
-{
-	switch (n) {
-		case 0:
-			return;
-		case 1:
-			*(char *)to = __get_user((const char *) from, 1);
-			return;
-		case 2:
-			*(short *)to = __get_user((const short *) from, 2);
-			return;
-		case 3:
-			*(short *) to = __get_user((const short *) from, 2);
-			*((char *) to + 2) = __get_user(2+(const char *) from, 1);
-			return;
-		case 4:
-			*(int *) to = __get_user((const int *) from, 4);
-			return;
-		case 8:
-			*(int *) to = __get_user((const int *) from, 4);
-			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
-			return;
-		case 12:
-			*(int *) to = __get_user((const int *) from, 4);
-			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
-			*(2+(int *) to) = __get_user(2+(const int *) from, 4);
-			return;
-		case 16:
-			*(int *) to = __get_user((const int *) from, 4);
-			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
-			*(2+(int *) to) = __get_user(2+(const int *) from, 4);
-			*(3+(int *) to) = __get_user(3+(const int *) from, 4);
-			return;
-	}
-#define COMMON(x) \
-__asm__("cld\n\t" \
-	"rep ; fs ; movsl\n\t" \
-	x \
-	: /* no outputs */ \
-	:"c" (n/4),"D" ((long) to),"S" ((long) from) \
-	:"cx","di","si","memory")
-
-	switch (n % 4) {
-		case 0:
-			COMMON("");
-			return;
-		case 1:
-			COMMON("fs ; movsb");
-			return;
-		case 2:
-			COMMON("fs ; movsw");
-			return;
-		case 3:
-			COMMON("fs ; movsw\n\tfs ; movsb");
-			return;
-	}
-#undef COMMON
-}
-
-#define memcpy_fromfs(to, from, n) \
-(__builtin_constant_p(n) ? \
- __constant_memcpy_fromfs((to),(from),(n)) : \
- __generic_memcpy_fromfs((to),(from),(n)))
-
-#define memcpy_tofs(to, from, n) \
-(__builtin_constant_p(n) ? \
- __constant_memcpy_tofs((to),(from),(n)) : \
- __generic_memcpy_tofs((to),(from),(n)))
+#define put_user(x,ptr)	do { (*(ptr)=(x)); } while (0)
+#define get_user(ptr)	(*(ptr))
 
 /*
  * These are deprecated..
@@ -266,72 +25,38 @@
  * Use "put_user()" and "get_user()" with the proper pointer types instead.
  */
 
-#define get_fs_byte(addr) __get_user((const unsigned char *)(addr),1)
-#define get_fs_word(addr) __get_user((const unsigned short *)(addr),2)
-#define get_fs_long(addr) __get_user((const unsigned int *)(addr),4)
-
-#define put_fs_byte(x,addr) __put_user((x),(unsigned char *)(addr),1)
-#define put_fs_word(x,addr) __put_user((x),(unsigned short *)(addr),2)
-#define put_fs_long(x,addr) __put_user((x),(unsigned int *)(addr),4)
+#define get_fs_byte(addr) get_user((const unsigned char *)(addr))
+#define get_fs_word(addr) get_user((const unsigned short *)(addr))
+#define get_fs_long(addr) get_user((const unsigned int *)(addr))
 
-#ifdef WE_REALLY_WANT_TO_USE_A_BROKEN_INTERFACE
+#define put_fs_byte(x,addr) put_user((x),(unsigned char *)(addr))
+#define put_fs_word(x,addr) put_user((x),(unsigned short *)(addr))
+#define put_fs_long(x,addr) put_user((x),(unsigned int *)(addr))
 
-static inline unsigned short get_user_word(const short *addr)
+static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
-	return __get_user(addr, 2);
+	memcpy(to, from, n);
 }
 
-static inline unsigned char get_user_byte(const char * addr)
+static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
 {
-	return __get_user(addr,1);
+	memcpy(to, from, n);
 }
 
-static inline unsigned long get_user_long(const int *addr)
-{
-	return __get_user(addr, 4);
-}
-
-static inline void put_user_byte(char val,char *addr)
-{
-	__put_user(val, addr, 1);
-}
-
-static inline void put_user_word(short val,short * addr)
-{
-	__put_user(val, addr, 2);
-}
-
-static inline void put_user_long(unsigned long val,int * addr)
-{
-	__put_user(val, addr, 4);
-}
-
-#endif
-
 /*
- * Someone who knows GNU asm better than I should double check the following.
- * It seems to work, but I don't know if I'm doing something subtly wrong.
- * --- TYT, 11/24/91
- * [ nothing wrong here, Linus: I just changed the ax to be any reg ]
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ * 
+ * For historical reasons, these macros are grossly misnamed.
  */
-
-static inline unsigned long get_fs(void)
-{
-	unsigned long _v;
-	__asm__("mov %%fs,%w0":"=r" (_v):"0" (0));
-	return _v;
-}
+      
+#define get_fs()	(current->tss.segment)
+#define set_fs(x)	(current->tss.segment = (x))
 
 static inline unsigned long get_ds(void)
 {
-	unsigned long _v;
-	__asm__("mov %%ds,%w0":"=r" (_v):"0" (0));
-	return _v;
-}
-
-static inline void set_fs(unsigned long val)
-{
-	__asm__ __volatile__("mov %w0,%%fs": /* no output */ :"r" (val));
+	return KERNEL_DS;
 }
 
 #endif /* __ASSEMBLY__ */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- lx2.0/v2.0.21/linux/include/asm-i386/system.h	Mon Aug  5 10:13:54 1996
+++ linux/include/asm-i386/system.h	Tue Sep 24 14:07:21 1996
@@ -96,6 +96,7 @@
 		loaddebug(prev,2); \
 		loaddebug(prev,3); \
 		loaddebug(prev,6); \
+		loaddebug(prev,7); \
 	} \
 } while (0)
 
@@ -117,6 +118,7 @@
 		loaddebug(prev,2); \
 		loaddebug(prev,3); \
 		loaddebug(prev,6); \
+		loaddebug(prev,7); \
 	} \
 } while (0)
 #endif
@@ -275,7 +277,7 @@
 	"movb %%ah,%6\n\t" \
 	"rorl $16,%%eax" \
 	: /* no output */ \
-	:"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
+	:"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
 	 "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
 	)
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/amigahw.h	Mon May 20 07:54:28 1996
+++ linux/include/asm-m68k/amigahw.h	Wed Sep 25 10:47:40 1996
@@ -195,6 +195,7 @@
 void amiga_chip_init (void);
 void *amiga_chip_alloc (long size);
 void amiga_chip_free (void *);
+unsigned long amiga_chip_avail( void ); /*MILAN*/
 
 struct tod3000 {
   unsigned int  :28, second2:4;	/* lower digit */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/amigaints.h linux/include/asm-m68k/amigaints.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/amigaints.h	Mon May 20 07:54:28 1996
+++ linux/include/asm-m68k/amigaints.h	Wed Sep 25 10:47:41 1996
@@ -18,7 +18,9 @@
 **
 */
 
-#define NUM_AMIGA_SOURCES   (24)
+#define AMI_IRQS            (24)
+#define AMI_STD_IRQS        (14)
+#define CIA_IRQS            (5)
 
 /* vertical blanking interrupt */
 #define IRQ_AMIGA_VERTB     (IRQ_MACHSPEC | 0)
@@ -43,22 +45,26 @@
 #define IRQ_AMIGA_RBF	    (IRQ_MACHSPEC | 9)
 #define IRQ_AMIGA_TBE	    (IRQ_MACHSPEC | 10)
 
-/* CIA interrupt sources */
-#define IRQ_AMIGA_CIAA_TA   (IRQ_MACHSPEC | 11)
-#define IRQ_AMIGA_CIAA_TB   (IRQ_MACHSPEC | 12)
-#define IRQ_AMIGA_CIAA_ALRM (IRQ_MACHSPEC | 13)
-#define IRQ_AMIGA_CIAA_SP   (IRQ_MACHSPEC | 14)
-#define IRQ_AMIGA_CIAA_FLG  (IRQ_MACHSPEC | 15)
-#define IRQ_AMIGA_CIAB_TA   (IRQ_MACHSPEC | 16)
-#define IRQ_AMIGA_CIAB_TB   (IRQ_MACHSPEC | 17)
-#define IRQ_AMIGA_CIAB_ALRM (IRQ_MACHSPEC | 18)
-#define IRQ_AMIGA_CIAB_SP   (IRQ_MACHSPEC | 19)
-#define IRQ_AMIGA_CIAB_FLG  (IRQ_MACHSPEC | 20)
+/* software interrupts */
+#define IRQ_AMIGA_SOFT      (IRQ_MACHSPEC | 11)
 
-#define IRQ_AMIGA_SOFT      (IRQ_MACHSPEC | 21)
+/* interrupts from external hardware */
+#define IRQ_AMIGA_PORTS	    (IRQ_MACHSPEC | 12)
+#define IRQ_AMIGA_EXTER	    (IRQ_MACHSPEC | 13)
 
-#define IRQ_AMIGA_PORTS	    (IRQ_MACHSPEC | 22)
-#define IRQ_AMIGA_EXTER	    (IRQ_MACHSPEC | 23)
+/* CIA interrupt sources */
+#define IRQ_AMIGA_CIAA      (IRQ_MACHSPEC | 14)
+#define IRQ_AMIGA_CIAA_TA   (IRQ_MACHSPEC | 14)
+#define IRQ_AMIGA_CIAA_TB   (IRQ_MACHSPEC | 15)
+#define IRQ_AMIGA_CIAA_ALRM (IRQ_MACHSPEC | 16)
+#define IRQ_AMIGA_CIAA_SP   (IRQ_MACHSPEC | 17)
+#define IRQ_AMIGA_CIAA_FLG  (IRQ_MACHSPEC | 18)
+#define IRQ_AMIGA_CIAB      (IRQ_MACHSPEC | 19)
+#define IRQ_AMIGA_CIAB_TA   (IRQ_MACHSPEC | 19)
+#define IRQ_AMIGA_CIAB_TB   (IRQ_MACHSPEC | 20)
+#define IRQ_AMIGA_CIAB_ALRM (IRQ_MACHSPEC | 21)
+#define IRQ_AMIGA_CIAB_SP   (IRQ_MACHSPEC | 22)
+#define IRQ_AMIGA_CIAB_FLG  (IRQ_MACHSPEC | 23)
 
 #define IRQ_FLOPPY	    IRQ_AMIGA_DSKBLK
 
@@ -88,12 +94,30 @@
 #define IF_DSKBLK   0x0002	/* diskblock DMA finished */
 #define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
 
+struct irq_server {
+	unsigned short count, reentrance;
+};
+
+extern void amiga_do_irq(int irq, struct pt_regs *fp);
+extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
+
 /* CIA interrupt control register bits */
 
-#define CIA_ICR_TA   0x01
-#define CIA_ICR_TB   0x02
-#define CIA_ICR_ALRM 0x04
-#define CIA_ICR_SP   0x08
-#define CIA_ICR_FLG  0x10
+#define CIA_ICR_TA	0x01
+#define CIA_ICR_TB	0x02
+#define CIA_ICR_ALRM	0x04
+#define CIA_ICR_SP	0x08
+#define CIA_ICR_FLG	0x10
+#define CIA_ICR_ALL	0x1f
+#define CIA_ICR_SETCLR	0x80
+
+/* to access the interrupt control registers of CIA's use only
+** these functions, they behave exactly like the amiga os routines
+*/
+
+extern struct ciabase ciaa_base, ciab_base;
+
+extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask);
+extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask);
 
 #endif /* asm-m68k/amigaints.h */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/atari_acsi.h linux/include/asm-m68k/atari_acsi.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/atari_acsi.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_acsi.h	Wed Sep 25 10:47:41 1996
@@ -0,0 +1,37 @@
+#ifndef _ASM_ATARI_ACSI_H
+#define _ASM_ATARI_ACSI_H
+
+/* Functions exported by drivers/block/acsi.c */
+
+void acsi_delay_start( void );
+void acsi_delay_end( long usec );
+int acsi_wait_for_IRQ( unsigned timeout );
+int acsi_wait_for_noIRQ( unsigned timeout );
+int acsicmd_nodma( const char *cmd, int enable);
+int acsi_getstatus( void );
+int acsi_extstatus( char *buffer, int cnt );
+void acsi_end_extstatus( void );
+int acsi_extcmd( unsigned char *buffer, int cnt );
+
+/* The ACSI buffer is guarantueed to reside in ST-RAM and may be used by other
+ * drivers that work on the ACSI bus, too. It's data are valid only as long as
+ * the ST-DMA is locked. */
+extern char *acsi_buffer;
+extern unsigned long phys_acsi_buffer;
+
+/* Utility macros */
+
+/* Send one data byte over the bus and set mode for next operation
+ * with one move.l -- Atari recommends this...
+ */
+
+#define DMA_LONG_WRITE(data,mode)							\
+    do {													\
+		*((unsigned long *)&dma_wd.fdc_acces_seccount) = 	\
+			((data)<<16) | (mode);							\
+	} while(0)
+
+#define ENABLE_IRQ()	atari_turnon_irq( IRQ_MFP_ACSI )
+#define DISABLE_IRQ()	atari_turnoff_irq( IRQ_MFP_ACSI )
+
+#endif /* _ASM_ATARI_ACSI_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/atari_rootsec.h linux/include/asm-m68k/atari_rootsec.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/atari_rootsec.h	Wed Dec 27 22:46:46 1995
+++ linux/include/asm-m68k/atari_rootsec.h	Wed Sep 25 10:47:41 1996
@@ -29,6 +29,6 @@
   u_long bsl_st;		/* start of bad sector list */
   u_long bsl_cnt;		/* length of bad sector list */
   u_short checksum;		/* checksum for bootable disks */
-};
+} __attribute__((__packed__));
 
 #endif /* _LINUX_ATARI_ROOTSEC_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/atari_stdma.h linux/include/asm-m68k/atari_stdma.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/atari_stdma.h	Fri Apr 19 02:35:24 1996
+++ linux/include/asm-m68k/atari_stdma.h	Wed Sep 25 10:47:41 1996
@@ -8,7 +8,7 @@
 
 /***************************** Prototypes *****************************/
 
-void stdma_lock(isrfunc isr, void *data); 
+void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data); 
 void stdma_release( void );
 int stdma_others_waiting( void );
 int stdma_islocked( void );
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/atarihw.h	Mon May 20 07:54:28 1996
+++ linux/include/asm-m68k/atarihw.h	Wed Sep 25 10:47:41 1996
@@ -7,6 +7,10 @@
 ** 5/1/94 Roman Hodek:
 **   Added definitions for TT specific chips.
 **
+** 1996-09-13 lars brinkhoff <f93labr@dd.chalmers.se>:
+**   Finally added definitions for the matrix/codec and the DSP56001 host
+**   interface.
+**
 ** 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.
@@ -48,7 +52,7 @@
 
 {
 	if (writeflag) {
-		if (!is_medusa || m68k_is040or060 == 6)
+		if (!is_medusa || CPU_IS_060)
 			cache_push( paddr, len );
 	}
 	else {
@@ -273,9 +277,47 @@
 
 /* 
 ** Falcon DMA Sound Subsystem
-** not implemented yet
  */     
 
+#define MATRIX_BASE (0xffff8930)
+struct MATRIX
+{
+  u_short source;
+  u_short destination;
+  u_char external_frequency_divider;
+  u_char internal_frequency_divider;
+};
+#define matrix (*(volatile struct MATRIX *)MATRIX_BASE)
+
+#define CODEC_BASE (0xffff8936)
+struct CODEC
+{
+  u_char tracks;
+  u_char input_source;
+#define CODEC_SOURCE_MATRIX     1
+#define CODEC_SOURCE_ADC        2
+  u_char adc_source;
+#define ADC_SOURCE_RIGHT_PSG    1
+#define ADC_SOURCE_LEFT_PSG     2
+  u_char gain;
+#define CODEC_GAIN_RIGHT        0x0f
+#define CODEC_GAIN_LEFT         0xf0
+  u_char attenuation;
+#define CODEC_ATTENUATION_RIGHT 0x0f
+#define CODEC_ATTENUATION_LEFT  0xf0
+  u_char unused1;
+  u_char status;
+#define CODEC_OVERFLOW_RIGHT    1
+#define CODEC_OVERFLOW_LEFT     2
+  u_char unused2, unused3, unused4, unused5;
+  u_char gpio_directions;
+#define GPIO_IN                 0
+#define GPIO_OUT                1
+  u_char unused6;
+  u_char gpio_data;
+};
+#define codec (*(volatile struct CODEC *)CODEC_BASE)
+
 /*
 ** Falcon Blitter
 */
@@ -321,13 +363,13 @@
  };
 # define scc ((*(volatile struct SCC*)SCC_BAS))
 
-/* The ESCC (Z85230) in an Atari ST. The channels are revered! */
+/* The ESCC (Z85230) in an Atari ST. The channels are reversed! */
 # define st_escc ((*(volatile struct SCC*)0xfffffa31))
 # define st_escc_dsr ((*(volatile char *)0xfffffa39))
 
 /* TT SCC DMA Controller (same chip as SCSI DMA) */
 
-#define	TT_SCC_DMA_BAS	(0xffff8c01)
+#define	TT_SCC_DMA_BAS	(0xffff8c00)
 #define	tt_scc_dma	((*(volatile struct TT_DMA *)TT_SCC_DMA_BAS))
 
 /*
@@ -344,8 +386,41 @@
 
 /*
 ** Falcon DSP Host Interface
-** not implemented yet
  */
+
+#define DSP56K_HOST_INTERFACE_BASE (0xffffa200)
+struct DSP56K_HOST_INTERFACE {
+  u_char icr;
+#define DSP56K_ICR_RREQ	0x01
+#define DSP56K_ICR_TREQ	0x02
+#define DSP56K_ICR_HF0	0x08
+#define DSP56K_ICR_HF1	0x10
+#define DSP56K_ICR_HM0	0x20
+#define DSP56K_ICR_HM1	0x40
+#define DSP56K_ICR_INIT	0x80
+  
+  u_char cvr;
+#define DSP56K_CVR_HV_MASK 0x1f
+#define DSP56K_CVR_HC	0x80
+
+  u_char isr;
+#define DSP56K_ISR_RXDF	0x01
+#define DSP56K_ISR_TXDE	0x02
+#define DSP56K_ISR_TRDY	0x04
+#define DSP56K_ISR_HF2	0x08
+#define DSP56K_ISR_HF3	0x10
+#define DSP56K_ISR_DMA	0x40
+#define DSP56K_ISR_HREQ	0x80
+  
+  u_char ivr;
+
+  union {
+    u_char b[4];
+    u_short w[2];
+    u_long l;
+  } data;
+};
+#define dsp56k_host_interface ((*(volatile struct DSP56K_HOST_INTERFACE *)DSP56K_HOST_INTERFACE_BASE))
  
 /*
 ** MFP 68901
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/atariints.h linux/include/asm-m68k/atariints.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/atariints.h	Mon May 20 07:54:28 1996
+++ linux/include/asm-m68k/atariints.h	Wed Sep 25 10:47:41 1996
@@ -216,5 +216,6 @@
 }
 
 unsigned long atari_register_vme_int( void );
+void atari_unregister_vme_int( unsigned long );
 
 #endif /* linux/atariints.h */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/bitops.h	Mon May 20 07:54:29 1996
+++ linux/include/asm-m68k/bitops.h	Wed Sep 25 10:47:41 1996
@@ -59,11 +59,11 @@
 	if (!size)
 		return 0;
 
+	size = (size >> 5) + ((size & 31) > 0);
 	while (*p++ == allones)
 	{
-		if (size <= 32)
+		if (--size == 0)
 			return (p - addr) << 5;
-		size -= 32;
 	}
 
 	num = ~*--p;
@@ -123,11 +123,11 @@
 	if (!size)
 		return 0;
 
+	size = (size >> 4) + ((size & 15) > 0);
 	while (*p++ == 0xffff)
 	{
-		if (size <= 16)
+		if (--size == 0)
 			return (p - addr) << 4;
-		size -= 16;
 	}
 
 	num = ~*--p;
@@ -203,11 +203,11 @@
 	if (!size)
 		return 0;
 
+	size = (size >> 5) + ((size & 31) > 0);
 	while (*p++ == ~0UL)
 	{
-		if (size <= 32)
+		if (--size == 0)
 			return (p - addr) << 5;
-		size -= 32;
 	}
 
 	--p;
@@ -237,6 +237,21 @@
 	/* No zero yet, search remaining full bytes for a zero */
 	res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
 	return (p - addr) * 32 + res;
+}
+
+/* Byte swapping. */
+
+extern __inline__ unsigned short
+swab16 (unsigned short val)
+{
+	return (val << 8) | (val >> 8);
+}
+
+extern __inline__ unsigned int
+swab32 (unsigned int val)
+{
+	__asm__ ("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val));
+	return val;
 }
 
 #endif /* _M68K_BITOPS_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/bootinfo.h	Mon May 20 07:54:29 1996
+++ linux/include/asm-m68k/bootinfo.h	Thu Jan  1 02:00:00 1970
@@ -1,289 +0,0 @@
-/*
-** asm/bootinfo.h -- Definition of the Linux/68K boot information structure
-**
-** Copyright 1992 by Greg Harp
-**
-** 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.
-**
-** Created 09/29/92 by Greg Harp
-**
-** 5/2/94 Roman Hodek:
-**   Added bi_atari part of the machine dependent union bi_un; for now it
-**	 contains just a model field to distinguish between TT and Falcon.
-*/
-
-#ifndef BOOTINFO_H
-#define BOOTINFO_H
-
-#include <asm/zorro.h>
-
-/*
- * Amiga specific part of bootinfo structure.
- */
-
-#define NUM_AUTO    16
-
-#ifndef __ASSEMBLY__
-
-#define AMIGAHW_DECLARE(name)	unsigned name : 1
-#define AMIGAHW_SET(name)	(boot_info.bi_amiga.hw_present.name = 1)
-#define AMIGAHW_PRESENT(name)	(boot_info.bi_amiga.hw_present.name)
-
-struct bi_Amiga {
-  int model;				/* Amiga Model (3000?) */
-  int num_autocon;			/* # of autoconfig devices found */
-  struct ConfigDev autocon[NUM_AUTO];	/* up to 16 autoconfig devices */
-#ifdef HACKER_KERNEL
-  void (*exit_func)(void);		/* addr of function to exit kernel */
-  unsigned long chip_addr;		/* start of chip memory (bytes) */
-#endif
-  unsigned long chip_size;		/* size of chip memory (bytes) */
-  unsigned char vblank; 		/* VBLANK frequency */
-  unsigned char psfreq; 		/* power supply frequency */
-  unsigned long eclock; 		/* EClock frequency */
-  unsigned long chipset;		/* native chipset present */
-  struct {
-    /* video hardware */
-    AMIGAHW_DECLARE(AMI_VIDEO);		/* Amiga Video */
-    AMIGAHW_DECLARE(AMI_BLITTER);	/* Amiga Blitter */
-    AMIGAHW_DECLARE(AMBER_FF);		/* Amber Flicker Fixer */
-    /* sound hardware */
-    AMIGAHW_DECLARE(AMI_AUDIO);		/* Amiga Audio */
-    /* disk storage interfaces */
-    AMIGAHW_DECLARE(AMI_FLOPPY);	/* Amiga Floppy */
-    AMIGAHW_DECLARE(A3000_SCSI);	/* SCSI (wd33c93, A3000 alike) */
-    AMIGAHW_DECLARE(A4000_SCSI);	/* SCSI (ncr53c710, A4000T alike) */
-    AMIGAHW_DECLARE(A1200_IDE);		/* IDE (A1200 alike) */
-    AMIGAHW_DECLARE(A4000_IDE);		/* IDE (A4000 alike) */
-    AMIGAHW_DECLARE(CD_ROM);		/* CD ROM drive */
-    /* other I/O hardware */
-    AMIGAHW_DECLARE(AMI_KEYBOARD);	/* Amiga Keyboard */
-    AMIGAHW_DECLARE(AMI_MOUSE);		/* Amiga Mouse */
-    AMIGAHW_DECLARE(AMI_SERIAL);	/* Amiga Serial */
-    AMIGAHW_DECLARE(AMI_PARALLEL);	/* Amiga Parallel */
-    /* real time clocks */
-    AMIGAHW_DECLARE(A2000_CLK);		/* Hardware Clock (A2000 alike) */
-    AMIGAHW_DECLARE(A3000_CLK);		/* Hardware Clock (A3000 alike) */
-    /* supporting hardware */
-    AMIGAHW_DECLARE(CHIP_RAM);		/* Chip RAM */
-    AMIGAHW_DECLARE(PAULA);		/* Paula (8364) */
-    AMIGAHW_DECLARE(DENISE);		/* Denise (8362) */
-    AMIGAHW_DECLARE(DENISE_HR);		/* Denise (8373) */
-    AMIGAHW_DECLARE(LISA);		/* Lisa (8375) */
-    AMIGAHW_DECLARE(AGNUS_PAL);		/* Normal/Fat PAL Agnus (8367/8371) */
-    AMIGAHW_DECLARE(AGNUS_NTSC);	/* Normal/Fat NTSC Agnus (8361/8370) */
-    AMIGAHW_DECLARE(AGNUS_HR_PAL);	/* Fat Hires PAL Agnus (8372) */
-    AMIGAHW_DECLARE(AGNUS_HR_NTSC);	/* Fat Hires NTSC Agnus (8372) */
-    AMIGAHW_DECLARE(ALICE_PAL);		/* PAL Alice (8374) */
-    AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
-    AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
-    AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
-  } hw_present;
-};
-
-#else	/* __ASSEMBLY__ */
- 
-BI_amiga_model		= BI_un
-BI_amiga_num_autcon	= BI_amiga_model+4
-BI_amiga_autocon	= BI_amiga_num_autcon+4
-#ifdef HACKER_KERNEL
-BI_amiga_exit_func	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
-BI_amiga_chip_addr	= BI_amiga_exit_func+4
-BI_amiga_chip_size	= BI_amiga_chip_addr+4
-#else
-BI_amiga_chip_size	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
-#endif
-BI_amiga_vblank		= BI_amiga_chip_size+4
-BI_amiga_psfreq		= BI_amiga_vblank+1
-BI_amiga_eclock		= BI_amiga_psfreq+1
-BI_amiga_chipset	= BI_amiga_eclock+4
-BI_amiga_hw_present	= BI_amiga_chipset+4
-
-#endif	/* __ASSEMBLY__ */
-
-/* Atari specific part of bootinfo */
-
-/*
- * Define several Hardware-Chips for indication so that for the ATARI we do
- * no longer decide whether it is a Falcon or other machine . It's just
- * important what hardware the machine uses
- */
-
-/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */
-
-#ifndef __ASSEMBLY__
-
-#define ATARIHW_DECLARE(name)	unsigned name : 1
-#define ATARIHW_SET(name)	(boot_info.bi_atari.hw_present.name = 1)
-#define ATARIHW_PRESENT(name)	(boot_info.bi_atari.hw_present.name)
-
-struct bi_Atari {
-  struct {
-    /* video hardware */
-    ATARIHW_DECLARE(STND_SHIFTER);	/* ST-Shifter - no base low ! */
-    ATARIHW_DECLARE(EXTD_SHIFTER);	/* STe-Shifter - 24 bit address */
-    ATARIHW_DECLARE(TT_SHIFTER);	/* TT-Shifter */
-    ATARIHW_DECLARE(VIDEL_SHIFTER);	/* Falcon-Shifter */
-    /* sound hardware */
-    ATARIHW_DECLARE(YM_2149);		/* Yamaha YM 2149 */
-    ATARIHW_DECLARE(PCM_8BIT);		/* PCM-Sound in STe-ATARI */
-    ATARIHW_DECLARE(CODEC);		/* CODEC Sound (Falcon) */
-    /* disk storage interfaces */
-    ATARIHW_DECLARE(TT_SCSI);		/* Directly mapped NCR5380 */
-    ATARIHW_DECLARE(ST_SCSI);		/* NCR5380 via ST-DMA (Falcon) */
-    ATARIHW_DECLARE(ACSI);		/* Standard ACSI like in STs */
-    ATARIHW_DECLARE(IDE);		/* IDE Interface */
-    ATARIHW_DECLARE(FDCSPEED);		/* 8/16 MHz switch for FDC */
-    /* other I/O hardware */
-    ATARIHW_DECLARE(ST_MFP);		/* The ST-MFP (there should
-					   be no Atari without
-					   it... but who knows?) */
-    ATARIHW_DECLARE(TT_MFP);		/* 2nd MFP */
-    ATARIHW_DECLARE(SCC);		/* Serial Communications Contr. */
-    ATARIHW_DECLARE(ST_ESCC);		/* SCC Z83230 in an ST */
-    ATARIHW_DECLARE(ANALOG_JOY);	/* Paddle Interface for STe
-					   and Falcon */
-    ATARIHW_DECLARE(MICROWIRE);		/* Microwire Interface */
-    /* DMA */
-    ATARIHW_DECLARE(STND_DMA);		/* 24 Bit limited ST-DMA */
-    ATARIHW_DECLARE(EXTD_DMA);		/* 32 Bit ST-DMA */
-    ATARIHW_DECLARE(SCSI_DMA);		/* DMA for the NCR5380 */
-    ATARIHW_DECLARE(SCC_DMA);		/* DMA for the SCC */
-    /* real time clocks */
-    ATARIHW_DECLARE(TT_CLK);		/* TT compatible clock chip */
-    ATARIHW_DECLARE(MSTE_CLK);		/* Mega ST(E) clock chip */
-    /* supporting hardware */
-    ATARIHW_DECLARE(SCU);		/* System Control Unit */
-    ATARIHW_DECLARE(BLITTER);		/* Blitter */
-    ATARIHW_DECLARE(VME);		/* VME Bus */
-  } hw_present;
-  unsigned long mch_cookie;		/* _MCH cookie from TOS */
-};
-
-/* mch_cookie values (upper word) */
-#define	ATARI_MCH_ST		0
-#define	ATARI_MCH_STE		1
-#define	ATARI_MCH_TT		2
-#define	ATARI_MCH_FALCON	3
-
-struct mem_info {
-  unsigned long addr;		/* physical address of memory chunk */
-  unsigned long size;		/* length of memory chunk (in bytes) */
-};
-
-#else	/* __ASSEMBLY__ */
-
-MI_addr		= 0
-MI_size		= MI_addr+4
-MI_sizeof	= MI_size+4
-
-#endif /* __ASSEMBLY__ */
-
-#define NUM_MEMINFO  4
-
-#define MACH_AMIGA   1
-#define MACH_ATARI   2
-#define MACH_MAC     3
-
-/*
- * CPU and FPU types
- */
-
-#define CPUB_68020 0
-#define CPUB_68030 1
-#define CPUB_68040 2
-#define CPUB_68060 3
-#define FPUB_68881 5
-#define FPUB_68882 6
-#define FPUB_68040 7	/* Internal FPU */
-#define FPUB_68060 8	/* Internal FPU */
-
-#define CPU_68020    (1<<CPUB_68020)
-#define CPU_68030    (1<<CPUB_68030)
-#define CPU_68040    (1<<CPUB_68040)
-#define CPU_68060    (1<<CPUB_68060)
-#define CPU_MASK     (31)
-#define FPU_68881    (1<<FPUB_68881)
-#define FPU_68882    (1<<FPUB_68882)
-#define FPU_68040    (1<<FPUB_68040)	/* Internal FPU */
-#define FPU_68060    (1<<FPUB_68060)	/* Internal FPU */
-
-#define CL_SIZE      (256)
-
-#ifndef __ASSEMBLY__
-
-#define MACH_IS_AMIGA	(boot_info.machtype == MACH_AMIGA)
-#define MACH_IS_ATARI	(boot_info.machtype == MACH_ATARI)
-
-struct bootinfo {
-  unsigned long machtype;		/* machine type */
-  unsigned long cputype;		/* system CPU & FPU */
-  struct mem_info memory[NUM_MEMINFO];	/* memory description */
-  int num_memory;			/* # of memory blocks found */
-  unsigned long ramdisk_size;		/* ramdisk size in 1024 byte blocks */
-  unsigned long ramdisk_addr;		/* address of the ram disk in mem */
-  char command_line[CL_SIZE];		/* kernel command line parameters */
-  union {
-    struct bi_Amiga bi_ami; 	/* Amiga specific information */
-    struct bi_Atari bi_ata; 	/* Atari specific information */
-  } bi_un;
-};
-#define bi_amiga bi_un.bi_ami
-#define bi_atari bi_un.bi_ata
-#define bi_mac	 bi_un.bi_mac
-
-extern struct bootinfo
-    boot_info;
-
-#else	/* __ASSEMBLY__ */
-
-BI_machtype	= 0
-BI_cputype	= BI_machtype+4
-BI_memory	= BI_cputype+4
-BI_num_memory	= BI_memory+(MI_sizeof*NUM_MEMINFO)
-BI_ramdisk_size	= BI_num_memory+4
-BI_ramdisk_addr	= BI_ramdisk_size+4
-BI_command_line	= BI_ramdisk_addr+4
-BI_un		= BI_command_line+CL_SIZE
-
-#endif /* __ASSEMBLY__ */
-
-
-/*
- * Stuff for bootinfo interface versioning
- *
- * At the start of kernel code, a 'struct bootversion' is located. bootstrap
- * checks for a matching version of the interface before booting a kernel, to
- * avoid user confusion if kernel and bootstrap don't work together :-)
- *
- * If incompatible changes are made to the bootinfo interface, the major
- * number below should be stepped (and the minor reset to 0) for the
- * appropriate machine. If a change is backward-compatible, the minor should
- * be stepped. "Backwards-compatible" means that booting will work, but
- * certain features may not.
- */
-
-#define BOOTINFOV_MAGIC			0x4249561A	/* 'BIV^Z' */
-#define MK_BI_VERSION(major,minor)	(((major)<<16)+(minor))
-#define BI_VERSION_MAJOR(v)		(((v) >> 16) & 0xffff)
-#define BI_VERSION_MINOR(v)		((v) & 0xffff)
-
-#ifndef __ASSEMBLY__
-
-struct bootversion {
-    unsigned short branch;
-    unsigned long magic;
-    struct {
-       unsigned long machtype;
-       unsigned long version;
-    } machversions[0];
-};
-
-#endif /* __ASSEMBLY__ */
-
-#define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
-#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
-
-#endif /* BOOTINFO_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/byteorder.h	Sun Mar 31 01:09:52 1996
+++ linux/include/asm-m68k/byteorder.h	Wed Sep 25 10:47:41 1996
@@ -1,14 +1,47 @@
 #ifndef _M68K_BYTEORDER_H
 #define _M68K_BYTEORDER_H
 
-#ifdef __KERNEL__
-#define __BIG_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
 #endif
+
+#ifndef __BIG_ENDIAN_BITFIELD
 #define __BIG_ENDIAN_BITFIELD
+#endif
+
+#undef ntohl
+#undef ntohs
+#undef htonl
+#undef htons
+
+extern unsigned long int	ntohl(unsigned long int);
+extern unsigned short int	ntohs(unsigned short int);
+extern unsigned long int	htonl(unsigned long int);
+extern unsigned short int	htons(unsigned short int);
+
+extern __inline__ unsigned long int	__ntohl(unsigned long int);
+extern __inline__ unsigned short int	__ntohs(unsigned short int);
 
-#define ntohl(x) x
-#define ntohs(x) x
-#define htonl(x) x
-#define htons(x) x
+extern __inline__ unsigned long int
+__ntohl(unsigned long int x)
+{
+	return x;
+}
+
+extern __inline__ unsigned short int
+__ntohs(unsigned short int x)
+{
+	return x;
+}
+
+#define __htonl(x) __ntohl(x)
+#define __htons(x) __ntohs(x)
+
+#ifdef __OPTIMIZE__
+#define ntohl(x) __ntohl(x)
+#define ntohs(x) __ntohs(x)
+#define htonl(x) __htonl(x)
+#define htons(x) __htons(x)
+#endif
 
 #endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/delay.h linux/include/asm-m68k/delay.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/delay.h	Thu May 16 09:05:11 1996
+++ linux/include/asm-m68k/delay.h	Wed Sep 25 10:47:41 1996
@@ -7,13 +7,10 @@
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
 
-extern __inline__ void __delay(int loops)
+extern __inline__ void __delay(unsigned long loops)
 {
-	__asm__ __volatile__ ("\n\tmovel %0,%/d0\n1:\tsubql #1,%/d0\n\t"
-			      "bpls 1b\n"
-		: /* no outputs */
-		: "g" (loops)
-		: "d0");
+	__asm__ __volatile__ ("1: subql #1,%0; jcc 1b"
+		: "=d" (loops) : "0" (loops));
 }
 
 /*
@@ -25,23 +22,22 @@
  */
 extern __inline__ void udelay(unsigned long usecs)
 {
-	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
+	unsigned long tmp;
 
-	__asm__ __volatile__ ("mulul %1,%0:%2"
-	     : "=d" (usecs)
-	     : "d" (usecs),
-	       "d" (loops_per_sec));
+	usecs *= 4295;		/* 2**32 / 1000000 */
+	__asm__ ("mulul %2,%0:%1"
+		: "=d" (usecs), "=d" (tmp)
+		: "d" (usecs), "1" (loops_per_sec));
 	__delay(usecs);
 }
 
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
-	__asm__ ("mulul %1,%/d0:%0\n\tdivul %2,%/d0:%0"
-		 :"=d" (a)
-		 :"d" (b),
-		 "d" (c),
-		 "0" (a)
-		 :"d0");
+	unsigned long tmp;
+
+	__asm__ ("mulul %2,%0:%1; divul %3,%0:%1"
+		: "=d" (tmp), "=d" (a)
+		: "d" (b), "d" (c), "1" (a));
 	return a;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/errno.h linux/include/asm-m68k/errno.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/errno.h	Wed Dec 27 22:46:55 1995
+++ linux/include/asm-m68k/errno.h	Wed Sep 25 10:47:41 1996
@@ -58,7 +58,9 @@
 #define	ENOANO		55	/* No anode */
 #define	EBADRQC		56	/* Invalid request code */
 #define	EBADSLT		57	/* Invalid slot */
-#define	EDEADLOCK	58	/* File locking deadlock error */
+
+#define	EDEADLOCK	EDEADLK
+
 #define	EBFONT		59	/* Bad font file format */
 #define	ENOSTR		60	/* Device not a stream */
 #define	ENODATA		61	/* No data available */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/fcntl.h	Tue Apr 30 13:09:45 1996
+++ linux/include/asm-m68k/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -48,12 +48,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/ioctl.h linux/include/asm-m68k/ioctl.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/ioctl.h	Sat Mar 23 14:31:14 1996
+++ linux/include/asm-m68k/ioctl.h	Wed Sep 25 10:47:41 1996
@@ -1,4 +1,4 @@
-/* $Id: ioctl.h,v 1.4 1996/03/23 12:31:12 root Exp root $
+/* $Id: ioctl.h,v 1.1 1996/08/24 12:43:44 root Exp $
  *
  * linux/ioctl.h for Linux by H.H. Bergman.
  */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/irq.h linux/include/asm-m68k/irq.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/irq.h	Mon May 20 07:54:29 1996
+++ linux/include/asm-m68k/irq.h	Wed Sep 25 10:47:41 1996
@@ -7,15 +7,21 @@
 #include <linux/config.h>
 
 /*
+ * # of m68k interrupts
+ */
+
+#define SYS_IRQS 8
+
+/*
  * This should be the same as the max(NUM_X_SOURCES) for all the
  * different m68k hosts compiled into the kernel.
  * Currently the Atari has 72 and the Amiga 24, but if both are
  * supported in the kernel it is better to make room for 72.
  */
 #if defined(CONFIG_ATARI)
-#define NR_IRQS 72
+#define NR_IRQS (72+SYS_IRQS)
 #else
-#define NR_IRQS 24
+#define NR_IRQS (24+SYS_IRQS)
 #endif
 
 /*
@@ -28,19 +34,19 @@
  * that routine requires service.
  */
 
-#define IRQ1		 (1)    /* level 1 interrupt */
-#define IRQ2		 (2)    /* level 2 interrupt */
-#define IRQ3		 (3)    /* level 3 interrupt */
-#define IRQ4		 (4)    /* level 4 interrupt */
-#define IRQ5		 (5)    /* level 5 interrupt */
-#define IRQ6		 (6)    /* level 6 interrupt */
-#define IRQ7		 (7)    /* level 7 interrupt (non-maskable) */
+#define IRQ1		(1)	/* level 1 interrupt */
+#define IRQ2		(2)	/* level 2 interrupt */
+#define IRQ3		(3)	/* level 3 interrupt */
+#define IRQ4		(4)	/* level 4 interrupt */
+#define IRQ5		(5)	/* level 5 interrupt */
+#define IRQ6		(6)	/* level 6 interrupt */
+#define IRQ7		(7)	/* level 7 interrupt (non-maskable) */
 
 /*
  * "Generic" interrupt sources
  */
 
-#define IRQ_SCHED_TIMER  (8)    /* interrupt source for scheduling timer */
+#define IRQ_SCHED_TIMER	(8)    /* interrupt source for scheduling timer */
 
 /*
  * Machine specific interrupt sources.
@@ -50,67 +56,46 @@
  * The machine specific files define these sources.
  */
 
-#define IRQ_MACHSPEC	 (0x10000000L)
+#define IRQ_MACHSPEC	(0x10000000L)
+#define IRQ_IDX(irq)	((irq) & ~IRQ_MACHSPEC)
 
-#ifndef ISRFUNC_T
-struct pt_regs;
-typedef void (*isrfunc) (int irq, struct pt_regs * regs, void *data);
-#define ISRFUNC_T
-#endif /* ISRFUNC_T */
+/*
+ * various flags for request_irq()
+ */
+#define IRQ_FLG_LOCK	(0x0001)	/* handler is not replaceable	*/
+#define IRQ_FLG_REPLACE	(0x0002)	/* replace existing handler	*/
+#define IRQ_FLG_FAST	(0x0004)
+#define IRQ_FLG_SLOW	(0x0008)
+#define IRQ_FLG_STD	(0x8000)	/* internally used		*/
 
 /*
  * This structure is used to chain together the ISRs for a particular
  * interrupt source (if it supports chaining).
  */
-typedef struct isr_node {
-    isrfunc	    isr;
-    int 	    pri;
-    void            *data;
-    char	    *name;
-    struct isr_node *next;
-} isr_node_t;
+typedef struct irq_node {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+	struct irq_node *next;
+} irq_node_t;
+
+/*
+ * This structure has only 4 elements for speed reasons
+ */
+typedef struct irq_handler {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+} irq_handler_t;
 
 /* count of spurious interrupts */
-extern volatile unsigned long num_spurious;
-
-/*
- * This function returns a new isr_node_t
- */
-extern isr_node_t *new_isr_node(void);
-
-/*
- * This function is used to add a specific interrupt service routine
- * for the specified interrupt source.
- *
- * If the source is machine specific, it will be passed along to the
- * machine specific routine.
- *
- * "data" is user specified data which will be passed to the isr routine.
- *
- * (isrfunc is defined in linux/config.h)
- */
-extern int add_isr (unsigned long source, isrfunc isr, int pri, void
-		    *data, char *name);
-
-/*
- * This routine will remove an isr for the specified interrupt source.
- */
-extern int remove_isr (unsigned long source, isrfunc isr, void *data);
-
-/*
- * This routine will insert an isr_node_t into a chain of nodes, using
- * the priority stored in the node.
- */
-extern void insert_isr (isr_node_t **listp, isr_node_t *node);
-
-/*
- * This routine will delete the isr node for isr from a chain of nodes
- */
-extern void delete_isr (isr_node_t **listp, isrfunc isr, void *data);
+extern volatile unsigned int num_spurious;
 
 /*
- * This routine may be used to call the isr routines in the passed list.
+ * This function returns a new irq_node_t
  */
-extern void call_isr_list (int irq, isr_node_t *p, struct pt_regs *fp);
+extern irq_node_t *new_irq_node(void);
 
 #endif /* _M68K_IRQ_H_ */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/machdep.h	Mon May 20 07:54:29 1996
+++ linux/include/asm-m68k/machdep.h	Wed Sep 25 10:47:41 1996
@@ -8,24 +8,22 @@
 struct gendisk;
 struct buffer_head;
 
-#ifndef ISRFUNC_T
-typedef void (*isrfunc) (int irq, struct pt_regs *fp, void *data);
-#define ISRFUNC_T
-#endif /* ISRFUNC_T */
-
-extern void (*mach_sched_init)(isrfunc);
+extern void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
+/* machine dependent keyboard functions */
 extern int (*mach_keyb_init) (void);
 extern int (*mach_kbdrate) (struct kbd_repeat *);
 extern void (*mach_kbd_leds) (unsigned int);
-extern void (*mach_init_INTS) (void);
-extern int (*mach_add_isr) (unsigned long source, isrfunc handler,
-			    int pri, void *data, char *name);
-extern int (*mach_remove_isr) (unsigned long source, isrfunc handler,
-			       void *data);
-extern int (*mach_get_irq_list)(char *buf, int len);
-extern void (*mach_process_int) (int level, struct pt_regs *fp);
-extern void (*mach_enable_irq) (unsigned);
-extern void (*mach_disable_irq) (unsigned);
+/* machine dependent irq functions */
+extern void (*mach_init_IRQ) (void);
+extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
+extern int (*mach_request_irq) (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                                unsigned long flags, const char *devname, void *dev_id);
+extern int (*mach_free_irq) (unsigned int irq, void *dev_id);
+extern void (*mach_enable_irq) (unsigned int irq);
+extern void (*mach_disable_irq) (unsigned int irq);
+extern int (*mach_get_irq_list) (char *buf);
+extern void (*mach_process_int) (int irq, struct pt_regs *fp);
+/* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
 extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
 			   int *min, int *sec);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/page.h	Sat Mar 23 22:26:13 1996
+++ linux/include/asm-m68k/page.h	Wed Sep 25 10:47:41 1996
@@ -50,10 +50,6 @@
 
 #endif
 
-/* m68k_is040or060 is != 0 for a '040 or higher; used numbers are 4 for 68040
- * and 6 for 68060 */
-extern int m68k_is040or060;
-
 /* This is the cache mode to be used for pages containing page descriptors for
  * processors >= '040. It is in pte_mknocache(), and the variable is defined
  * and initialized in head.S */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/pgtable.h	Thu May 16 09:05:11 1996
+++ linux/include/asm-m68k/pgtable.h	Wed Sep 25 10:47:41 1996
@@ -1,6 +1,8 @@
 #ifndef _M68K_PGTABLE_H
 #define _M68K_PGTABLE_H
 
+#include<asm/setup.h>
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -8,17 +10,20 @@
  * the m68k page table tree.
  */
 
-#define __flush_tlb() \
-do { 	\
-	if (m68k_is040or060) \
-		__asm__ __volatile__(".word 0xf510\n"::); /* pflushan */ \
-	else \
-		__asm__ __volatile__("pflusha\n"::); \
-} while (0)
+/*
+ * flush all atc entries (user-space entries only for the 680[46]0).
+ */
+static inline void __flush_tlb(void)
+{
+	if (CPU_IS_040_OR_060)
+		__asm__ __volatile__(".word 0xf510\n"::); /* pflushan */
+	else
+		__asm__ __volatile__("pflusha\n"::);
+}
 
 static inline void __flush_tlb_one(unsigned long addr)
 {
-	if (m68k_is040or060) {
+	if (CPU_IS_040_OR_060) {
 		register unsigned long a0 __asm__ ("a0") = addr;
 		__asm__ __volatile__(".word 0xf508" /* pflush (%a0) */
 				     : : "a" (a0));
@@ -27,7 +32,17 @@
 }
 
 #define flush_tlb() __flush_tlb()
-#define flush_tlb_all() flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+	if (CPU_IS_040_OR_060)
+		__asm__ __volatile__(".word 0xf518\n"::); /* pflusha */
+	else
+		__asm__ __volatile__("pflusha\n"::);
+}
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
@@ -53,7 +68,12 @@
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define set_pte(pteptr, pteval) do{	\
+	((*(pteptr)) = (pteval));	\
+	if (CPU_IS_060)			\
+		__asm__ __volatile__(".word 0xf518\n"::); /* pflusha */ \
+	} while(0)
+
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define PMD_SHIFT	22
@@ -120,40 +140,49 @@
 #define _DESCTYPE_MASK	0x003
 
 #define _CACHEMASK040	(~0x060)
-#define _TABLE_MASK	(0xfffffff0)
+#define _TABLE_MASK	(0xfffffe00)
 
 #define _PAGE_TABLE	(_PAGE_SHORT)
 #define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
 
 #ifndef __ASSEMBLY__
 
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE040)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_CACHE040)
+extern unsigned long mm_cachebits;
+
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | mm_cachebits)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | mm_cachebits)
+
+/* Alternate definitions that are compile time constants, for
+   initializing protection_map.  The cachebits are fixed later.  */
+#define PAGE_NONE_C	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
+#define PAGE_SHARED_C	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_COPY_C	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
+#define PAGE_READONLY_C	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED)
 
 /*
  * The m68k can't do page protection for execute, and considers that the same are read.
  * Also, write permissions imply read permissions. This is the closest we can get..
  */
-#define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY
-#define __P010	PAGE_COPY
-#define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
-
-#define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
-#define __S110	PAGE_SHARED
-#define __S111	PAGE_SHARED
+#define __P000	PAGE_NONE_C
+#define __P001	PAGE_READONLY_C
+#define __P010	PAGE_COPY_C
+#define __P011	PAGE_COPY_C
+#define __P100	PAGE_READONLY_C
+#define __P101	PAGE_READONLY_C
+#define __P110	PAGE_COPY_C
+#define __P111	PAGE_COPY_C
+
+#define __S000	PAGE_NONE_C
+#define __S001	PAGE_READONLY_C
+#define __S010	PAGE_SHARED_C
+#define __S011	PAGE_SHARED_C
+#define __S100	PAGE_READONLY_C
+#define __S101	PAGE_READONLY_C
+#define __S110	PAGE_SHARED_C
+#define __S111	PAGE_SHARED_C
 
 /* zero page used for uninitialized stuff */
 extern unsigned long empty_zero_page;
@@ -295,9 +324,8 @@
 	tsk->tss.crp[0] = 0x80000000 | _PAGE_SHORT;
 	tsk->tss.crp[1] = tsk->tss.pagedir_p;
 	if (tsk == current) {
-		if (m68k_is040or060)
-			__asm__ __volatile__ (".word 0xf510\n\t" /* pflushan */
-					      "movel %0@,%/d0\n\t"
+		if (CPU_IS_040_OR_060)
+			__asm__ __volatile__ ("movel %0@,%/d0\n\t"
 					      ".long 0x4e7b0806\n\t"
 					      /* movec d0,urp */
 					      : : "a" (&tsk->tss.crp[1])
@@ -349,11 +377,17 @@
 
 extern inline void nocache_page (unsigned long vaddr)
 {
-	if (m68k_is040or060) {
+	if (CPU_IS_040_OR_060) {
 		pgd_t *dir;
 		pmd_t *pmdp;
 		pte_t *ptep;
 
+		if(CPU_IS_060)
+			__asm__ __volatile__ ("movel %0,%/a0\n\t"
+					      ".word 0xf470"
+					      : : "g" (VTOP(vaddr))
+					      : "a0");
+
 		dir = pgd_offset_k(vaddr);
 		pmdp = pmd_offset(dir,vaddr);
 		ptep = pte_offset(pmdp,vaddr);
@@ -363,7 +397,7 @@
 
 static inline void cache_page (unsigned long vaddr)
 {
-	if (m68k_is040or060) {
+	if (CPU_IS_040_OR_060) {
 		pgd_t *dir;
 		pmd_t *pmdp;
 		pte_t *ptep;
@@ -514,10 +548,10 @@
 
 #define flush_icache() \
 do { \
-	if (m68k_is040or060) \
-		asm ("nop; .word 0xf498 /* cinva %%ic */"); \
+	if (CPU_IS_040_OR_060) \
+		asm __volatile__ ("nop; .word 0xf498 /* cinva %%ic */"); \
 	else \
-		asm ("movec %/cacr,%/d0;" \
+		asm __volatile__ ("movec %/cacr,%/d0;" \
 		     "oriw %0,%/d0;" \
 		     "movec %/d0,%/cacr" \
 		     : /* no outputs */ \
@@ -552,7 +586,7 @@
    process changes.  */
 #define __flush_cache_all()						\
     do {								\
-	if (m68k_is040or060)					        \
+	if (CPU_IS_040_OR_060)					        \
                __asm__ __volatile__ ("nop; .word 0xf478\n" ::);         \
         else                                                            \
 	       __asm__ __volatile__ ("movec %%cacr,%%d0\n\t"		\
@@ -563,7 +597,7 @@
 
 #define __flush_cache_030()						\
     do {								\
-	if (m68k_is040or060 == 0)					\
+	if (CPU_IS_020_OR_030)					\
 	       __asm__ __volatile__ ("movec %%cacr,%%d0\n\t"		\
 				     "orw %0,%%d0\n\t"			\
 				     "movec %%d0,%%cacr"		\
@@ -574,7 +608,11 @@
 
 extern inline void flush_cache_mm(struct mm_struct *mm)
 {
+#if FLUSH_VIRTUAL_CACHE_040
 	if (mm == current->mm) __flush_cache_all();
+#else
+	if (mm == current->mm) __flush_cache_030();
+#endif
 }
 
 extern inline void flush_cache_range(struct mm_struct *mm,
@@ -582,9 +620,11 @@
 				     unsigned long end)
 {
 	if (mm == current->mm){
-	    if (m68k_is040or060)
+#if FLUSH_VIRTUAL_CACHE_040
+	    if (CPU_IS_040_OR_060)
 	        cache_push_v(start, end-start);
 	    else
+#endif
 	        __flush_cache_030();
 	}
 }
@@ -593,9 +633,11 @@
 				    unsigned long vmaddr)
 {
 	if (vma->vm_mm == current->mm){
-	    if (m68k_is040or060)
+#if FLUSH_VIRTUAL_CACHE_040
+	    if (CPU_IS_040_OR_060)
 	        cache_push_v(vmaddr, PAGE_SIZE);
 	    else
+#endif
 	        __flush_cache_030();
 	}
 }
@@ -603,7 +645,7 @@
 /* Push the page at kernel virtual address and clear the icache */
 extern inline void flush_page_to_ram (unsigned long address)
 {
-    if (m68k_is040or060) {
+    if (CPU_IS_040_OR_060) {
 	register unsigned long tmp __asm ("a0") = VTOP(address);
 	__asm__ __volatile__ ("nop\n\t"
 			      ".word 0xf470 /* cpushp %%dc,(%0) */\n\t"
@@ -620,7 +662,7 @@
 /* Push n pages at kernel virtual address and clear the icache */
 extern inline void flush_pages_to_ram (unsigned long address, int n)
 {
-    if (m68k_is040or060) {
+    if (CPU_IS_040_OR_060) {
 	while (n--) {
 	    register unsigned long tmp __asm ("a0") = VTOP(address);
 	    __asm__ __volatile__ ("nop\n\t"
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/posix_types.h linux/include/asm-m68k/posix_types.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/posix_types.h	Mon Jun  3 10:09:13 1996
+++ linux/include/asm-m68k/posix_types.h	Wed Sep 25 10:47:41 1996
@@ -1,5 +1,5 @@
-#ifndef __ARCH_I386_POSIX_TYPES_H
-#define __ARCH_I386_POSIX_TYPES_H
+#ifndef __ARCH_M68K_POSIX_TYPES_H
+#define __ARCH_M68K_POSIX_TYPES_H
 
 /*
  * This file is generally used by user-level software, so you need to
@@ -28,7 +28,11 @@
 #endif
 
 typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
 	int	val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+	int	__val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
 } __kernel_fsid_t;
 
 #undef	__FD_SET
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/processor.h	Sun Mar 24 12:21:16 1996
+++ linux/include/asm-m68k/processor.h	Wed Sep 25 10:47:42 1996
@@ -30,7 +30,7 @@
 #define wp_works_ok 1
 
 /* MAX floating point unit state size (FSAVE/FRESTORE) */
-#define FPSTATESIZE   (216/sizeof(unsigned short))
+#define FPSTATESIZE   (216/sizeof(unsigned char))
 
 /* 
  * if you change this structure, you must change the code and offsets
@@ -48,7 +48,7 @@
 	unsigned long  esp0;		/* points to SR of stack frame */
 	unsigned long  fp[8*3];
 	unsigned long  fpcntl[3];	/* fp control regs */
-	unsigned short fpstate[FPSTATESIZE];  /* floating point state */
+	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 }
@@ -59,7 +59,7 @@
 	NULL, 0, {0, 0}, 0 \
 }
 
-#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
+#define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
 #define free_kernel_stack(page) free_page((page))
 
 /*
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/resource.h	Sat Mar 23 14:56:25 1996
+++ linux/include/asm-m68k/resource.h	Wed Sep 25 10:47:42 1996
@@ -14,8 +14,9 @@
 #define RLIMIT_NPROC	6		/* max number of processes */
 #define RLIMIT_NOFILE	7		/* max number of open files */
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space*/
+#define RLIMIT_AS	9		/* address space limit */
 
-#define RLIM_NLIMITS	9
+#define RLIM_NLIMITS	10
 
 #ifdef __KERNEL__
 
@@ -29,6 +30,7 @@
   {LONG_MAX, LONG_MAX}, \
   {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
   {NR_OPEN, NR_OPEN},   \
+  {LONG_MAX, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}  \
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/segment.h	Thu May 16 09:05:11 1996
+++ linux/include/asm-m68k/segment.h	Wed Sep 25 10:47:42 1996
@@ -138,18 +138,18 @@
 	tmp = n;
 	n >>= 2;
 	if (n != 0)
-		__asm__ ("1:\t"
+		__asm__ __volatile__ ("1:\t"
 			 "movel %1@+,%/d0\n\t"
 			 "movesl %/d0,%2@+\n\t"
-			      "dbra %0,1b\n\t"
-			      "clrw %0\n\t"
-			      "subql #1,%0\n\t"
+			 "dbra %0,1b\n\t"
+			 "clrw %0\n\t"
+			 "subql #1,%0\n\t"
 			 "bccs 1b\n\t"
-			      : "=d" (n), "=a" (from), "=a" (to)
+			 : "=d" (n), "=a" (from), "=a" (to)
 			 : "0" (n-1), "1" (from), "2" (to)
 			 : "d0", "memory");
 	if (tmp & 2)
-		__asm__ ("movew %0@+,%/d0\n\t"
+		__asm__ __volatile__ ("movew %0@+,%/d0\n\t"
 			 "movesw %/d0,%1@+\n\t"
 			 : "=a" (from), "=a" (to)
 			 : "0" (from), "1" (to)
@@ -159,7 +159,7 @@
 			 "movesb %/d0,%1@\n\t"
 			 : /* no outputs */
 			 : "a" (from), "a" (to)
-			      : "d0", "memory");
+			 : "d0", "memory");
 }
 
 static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n)
@@ -234,18 +234,18 @@
 	tmp = n;
 	n >>= 2;
 	if (n != 0)
-		__asm__ ("1:\t"
+		__asm__ __volatile__ ("1:\t"
 			 "movesl %1@+,%/d0\n\t"
 			 "movel %/d0,%2@+\n\t"
-			      "dbra %0,1b\n\t"
-			      "clrw %0\n\t"
-			      "subql #1,%0\n\t"
+			 "dbra %0,1b\n\t"
+			 "clrw %0\n\t"
+			 "subql #1,%0\n\t"
 			 "bccs 1b\n\t"
-			      : "=d" (n), "=a" (from), "=a" (to)
+			 : "=d" (n), "=a" (from), "=a" (to)
 			 : "0" (n-1), "1" (from), "2" (to)
 			 : "d0", "memory");
 	if (tmp & 2)
-		__asm__ ("movesw %0@+,%/d0\n\t"
+		__asm__ __volatile__ ("movesw %0@+,%/d0\n\t"
 			 "movew %/d0,%1@+\n\t"
 			 : "=a" (from), "=a" (to)
 			 : "0" (from), "1" (to)
@@ -255,7 +255,7 @@
 			 "moveb %/d0,%1@\n\t"
 			 : /* no outputs */
 			 : "a" (from), "a" (to)
-			      : "d0", "memory");
+			 : "d0", "memory");
 }
 
 static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/semaphore.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/semaphore.h	Wed Sep 25 10:47:42 1996
@@ -0,0 +1,68 @@
+#ifndef _M68K_SEMAPHORE_H
+#define _M68K_SEMAPHORE_H
+
+#include <linux/linkage.h>
+
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * m68k version by Andreas Schwab
+ */
+
+struct semaphore {
+	int count;
+	int waiting;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+
+asmlinkage void down_failed(void /* special register calling convention */);
+asmlinkage void up_wakeup(void /* special register calling convention */);
+
+extern void __down(struct semaphore * sem);
+extern void __up(struct semaphore * sem);
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "down_failed" is a special asm handler that calls the C
+ * routine that actually waits. See arch/m68k/lib/semaphore.S
+ */
+extern inline void down(struct semaphore * sem)
+{
+	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+	__asm__ __volatile__(
+		"# atomic down operation\n"
+		"1:\n\t"
+		"lea %%pc@(1b),%%a0\n\t"
+		"subql #1,%0\n\t"
+		"jmi " SYMBOL_NAME_STR(down_failed)
+		: /* no outputs */
+		: "m" (sem->count), "a" (sem1)
+		: "%a0", "%d0", "%d1", "memory");
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+extern inline void up(struct semaphore * sem)
+{
+	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+	__asm__ __volatile__(
+		"# atomic up operation\n\t"
+		"lea %%pc@(1f),%%a0\n\t"
+		"addql #1,%0\n\t"
+		"jls " SYMBOL_NAME_STR(up_wakeup) "\n"
+		"1:"
+		: /* no outputs */
+		: "m" (sem->count), "a" (sem1)
+		: "%a0", "%d0", "%d1", "memory");
+}
+
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/setup.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/setup.h	Wed Sep 25 10:47:42 1996
@@ -0,0 +1,397 @@
+/*
+** asm/setup.h -- Definition of the Linux/m68k boot information structure
+**
+** Copyright 1992 by Greg Harp
+**
+** 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.
+**
+** Created 09/29/92 by Greg Harp
+**
+** 5/2/94 Roman Hodek:
+**   Added bi_atari part of the machine dependent union bi_un; for now it
+**   contains just a model field to distinguish between TT and Falcon.
+** 26/7/96 Roman Zippel:
+**   Renamed to setup.h; added some useful macros to allow gcc some
+**   optimizations if possible.
+*/
+
+#ifndef _M68K_SETUP_H
+#define _M68K_SETUP_H
+
+#include <linux/config.h>
+#include <asm/zorro.h>
+
+/*
+ * Amiga specific part of bootinfo structure.
+ */
+
+#define NUM_AUTO    16
+
+#ifndef __ASSEMBLY__
+
+#define AMIGAHW_DECLARE(name)	unsigned name : 1
+#define AMIGAHW_SET(name)	(boot_info.bi_amiga.hw_present.name = 1)
+#define AMIGAHW_PRESENT(name)	(boot_info.bi_amiga.hw_present.name)
+
+struct bi_Amiga {
+	int model;				/* Amiga Model (3000?) */
+	int num_autocon;			/* # of autoconfig devices found */
+	struct ConfigDev autocon[NUM_AUTO];	/* up to 16 autoconfig devices */
+#ifdef HACKER_KERNEL
+	void (*exit_func)(void);		/* addr of function to exit kernel */
+	unsigned long chip_addr;		/* start of chip memory (bytes) */
+#endif
+	unsigned long chip_size;		/* size of chip memory (bytes) */
+	unsigned char vblank;	 		/* VBLANK frequency */
+	unsigned char psfreq; 			/* power supply frequency */
+	unsigned long eclock; 			/* EClock frequency */
+	unsigned long chipset;			/* native chipset present */
+	struct {
+		/* video hardware */
+		AMIGAHW_DECLARE(AMI_VIDEO);	/* Amiga Video */
+		AMIGAHW_DECLARE(AMI_BLITTER);	/* Amiga Blitter */
+		AMIGAHW_DECLARE(AMBER_FF);	/* Amber Flicker Fixer */
+		/* sound hardware */
+		AMIGAHW_DECLARE(AMI_AUDIO);	/* Amiga Audio */
+		/* disk storage interfaces */
+		AMIGAHW_DECLARE(AMI_FLOPPY);	/* Amiga Floppy */
+		AMIGAHW_DECLARE(A3000_SCSI);	/* SCSI (wd33c93, A3000 alike) */
+		AMIGAHW_DECLARE(A4000_SCSI);	/* SCSI (ncr53c710, A4000T alike) */
+		AMIGAHW_DECLARE(A1200_IDE);	/* IDE (A1200 alike) */
+		AMIGAHW_DECLARE(A4000_IDE);	/* IDE (A4000 alike) */
+		AMIGAHW_DECLARE(CD_ROM);	/* CD ROM drive */
+		/* other I/O hardware */
+		AMIGAHW_DECLARE(AMI_KEYBOARD);	/* Amiga Keyboard */
+		AMIGAHW_DECLARE(AMI_MOUSE);	/* Amiga Mouse */
+		AMIGAHW_DECLARE(AMI_SERIAL);	/* Amiga Serial */
+		AMIGAHW_DECLARE(AMI_PARALLEL);	/* Amiga Parallel */
+		/* real time clocks */
+		AMIGAHW_DECLARE(A2000_CLK);	/* Hardware Clock (A2000 alike) */
+		AMIGAHW_DECLARE(A3000_CLK);	/* Hardware Clock (A3000 alike) */
+		/* supporting hardware */
+		AMIGAHW_DECLARE(CHIP_RAM);	/* Chip RAM */
+		AMIGAHW_DECLARE(PAULA);		/* Paula (8364) */
+		AMIGAHW_DECLARE(DENISE);	/* Denise (8362) */
+		AMIGAHW_DECLARE(DENISE_HR);	/* Denise (8373) */
+		AMIGAHW_DECLARE(LISA);		/* Lisa (8375) */
+		AMIGAHW_DECLARE(AGNUS_PAL);	/* Normal/Fat PAL Agnus (8367/8371) */
+		AMIGAHW_DECLARE(AGNUS_NTSC);	/* Normal/Fat NTSC Agnus (8361/8370) */
+		AMIGAHW_DECLARE(AGNUS_HR_PAL);	/* Fat Hires PAL Agnus (8372) */
+		AMIGAHW_DECLARE(AGNUS_HR_NTSC);	/* Fat Hires NTSC Agnus (8372) */
+		AMIGAHW_DECLARE(ALICE_PAL);	/* PAL Alice (8374) */
+		AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
+		AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
+		AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
+	} hw_present;
+};
+
+#else	/* __ASSEMBLY__ */
+ 
+BI_amiga_model		= BI_un
+BI_amiga_num_autcon	= BI_amiga_model+4
+BI_amiga_autocon	= BI_amiga_num_autcon+4
+#ifdef HACKER_KERNEL
+BI_amiga_exit_func	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
+BI_amiga_chip_addr	= BI_amiga_exit_func+4
+BI_amiga_chip_size	= BI_amiga_chip_addr+4
+#else
+BI_amiga_chip_size	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
+#endif
+BI_amiga_vblank		= BI_amiga_chip_size+4
+BI_amiga_psfreq		= BI_amiga_vblank+1
+BI_amiga_eclock		= BI_amiga_psfreq+1
+BI_amiga_chipset	= BI_amiga_eclock+4
+BI_amiga_hw_present	= BI_amiga_chipset+4
+
+#endif	/* __ASSEMBLY__ */
+
+/* Atari specific part of bootinfo */
+
+/*
+ * Define several Hardware-Chips for indication so that for the ATARI we do
+ * no longer decide whether it is a Falcon or other machine . It's just
+ * important what hardware the machine uses
+ */
+
+/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */
+
+#ifndef __ASSEMBLY__
+
+#define ATARIHW_DECLARE(name)	unsigned name : 1
+#define ATARIHW_SET(name)	(boot_info.bi_atari.hw_present.name = 1)
+#define ATARIHW_PRESENT(name)	(boot_info.bi_atari.hw_present.name)
+
+struct bi_Atari {
+	struct {
+		/* video hardware */
+		ATARIHW_DECLARE(STND_SHIFTER);	/* ST-Shifter - no base low ! */
+		ATARIHW_DECLARE(EXTD_SHIFTER);	/* STe-Shifter - 24 bit address */
+		ATARIHW_DECLARE(TT_SHIFTER);	/* TT-Shifter */
+		ATARIHW_DECLARE(VIDEL_SHIFTER);	/* Falcon-Shifter */
+		/* sound hardware */
+		ATARIHW_DECLARE(YM_2149);	/* Yamaha YM 2149 */
+		ATARIHW_DECLARE(PCM_8BIT);	/* PCM-Sound in STe-ATARI */
+		ATARIHW_DECLARE(CODEC);		/* CODEC Sound (Falcon) */
+		/* disk storage interfaces */
+		ATARIHW_DECLARE(TT_SCSI);	/* Directly mapped NCR5380 */
+		ATARIHW_DECLARE(ST_SCSI);	/* NCR5380 via ST-DMA (Falcon) */
+		ATARIHW_DECLARE(ACSI);		/* Standard ACSI like in STs */
+		ATARIHW_DECLARE(IDE);		/* IDE Interface */
+		ATARIHW_DECLARE(FDCSPEED);	/* 8/16 MHz switch for FDC */
+		/* other I/O hardware */
+		ATARIHW_DECLARE(ST_MFP);	/* The ST-MFP (there should
+						   be no Atari without
+						   it... but who knows?) */
+		ATARIHW_DECLARE(TT_MFP);	/* 2nd MFP */
+		ATARIHW_DECLARE(SCC);		/* Serial Communications Contr. */
+		ATARIHW_DECLARE(ST_ESCC);	/* SCC Z83230 in an ST */
+		ATARIHW_DECLARE(ANALOG_JOY);	/* Paddle Interface for STe
+						   and Falcon */
+		ATARIHW_DECLARE(MICROWIRE);	/* Microwire Interface */
+		/* DMA */
+		ATARIHW_DECLARE(STND_DMA);	/* 24 Bit limited ST-DMA */
+		ATARIHW_DECLARE(EXTD_DMA);	/* 32 Bit ST-DMA */
+		ATARIHW_DECLARE(SCSI_DMA);	/* DMA for the NCR5380 */
+		ATARIHW_DECLARE(SCC_DMA);	/* DMA for the SCC */
+		/* real time clocks */
+		ATARIHW_DECLARE(TT_CLK);	/* TT compatible clock chip */
+		ATARIHW_DECLARE(MSTE_CLK);	/* Mega ST(E) clock chip */
+		/* supporting hardware */
+		ATARIHW_DECLARE(SCU);		/* System Control Unit */
+		ATARIHW_DECLARE(BLITTER);	/* Blitter */
+		ATARIHW_DECLARE(VME);		/* VME Bus */
+	} hw_present;
+	unsigned long mch_cookie;		/* _MCH cookie from TOS */
+};
+
+/* mch_cookie values (upper word) */
+#define	ATARI_MCH_ST		0
+#define	ATARI_MCH_STE		1
+#define	ATARI_MCH_TT		2
+#define	ATARI_MCH_FALCON	3
+
+struct mem_info {
+	unsigned long addr;			/* physical address of memory chunk */
+	unsigned long size;			/* length of memory chunk (in bytes) */
+};
+
+#else	/* __ASSEMBLY__ */
+
+MI_addr		= 0
+MI_size		= MI_addr+4
+MI_sizeof	= MI_size+4
+
+#endif /* __ASSEMBLY__ */
+
+#define NUM_MEMINFO  4
+
+#define MACH_AMIGA   1
+#define MACH_ATARI   2
+#define MACH_MAC     3
+
+/*
+ * CPU and FPU types
+ */
+
+#define CPUB_68020 0
+#define CPUB_68030 1
+#define CPUB_68040 2
+#define CPUB_68060 3
+#define FPUB_68881 5
+#define FPUB_68882 6
+#define FPUB_68040 7				/* Internal FPU */
+#define FPUB_68060 8				/* Internal FPU */
+
+#define CPU_68020    (1<<CPUB_68020)
+#define CPU_68030    (1<<CPUB_68030)
+#define CPU_68040    (1<<CPUB_68040)
+#define CPU_68060    (1<<CPUB_68060)
+#define CPU_MASK     (31)
+#define FPU_68881    (1<<FPUB_68881)
+#define FPU_68882    (1<<FPUB_68882)
+#define FPU_68040    (1<<FPUB_68040)		/* Internal FPU */
+#define FPU_68060    (1<<FPUB_68060)		/* Internal FPU */
+#define FPU_MASK     (0xfe0)
+
+#define CL_SIZE      (256)
+
+/*
+ * machine type definitions
+ */
+
+#if !defined(CONFIG_AMIGA)
+#  define MACH_IS_AMIGA (0)
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#  define MACH_IS_AMIGA (boot_info.machtype == MACH_AMIGA)
+#else
+#  define CONFIG_AMIGA_ONLY
+#  define MACH_IS_AMIGA (1)
+#  define MACH_TYPE (MACH_AMIGA)
+#endif
+
+#if !defined(CONFIG_ATARI)
+#  define MACH_IS_ATARI (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+#  define MACH_IS_ATARI (boot_info.machtype == MACH_ATARI)
+#else
+#  define CONFIG_ATARI_ONLY
+#  define MACH_IS_ATARI (1)
+#  define MACH_TYPE (MACH_ATARI)
+#endif
+
+#if defined(CONFIG_MAC)
+#  error Currently no Mac support!
+#endif
+
+#ifndef MACH_TYPE
+#  define MACH_TYPE (boot_info.machtype)
+#endif
+
+/*
+ * cpu type definitions
+ */
+
+#if !defined(CONFIG_M68020)
+#  define CPU_IS_020 (0)
+#elif defined(CONFIG_M68030) || defined(CONFIG_M68040) || defined(CONFIG_M68060)
+#  define CPU_IS_020 (boot_info.cputype & CPU_68020)
+#else
+#  define CONFIG_M68020_ONLY
+#  define CPU_IS_020 (1)
+#endif
+
+#if !defined(CONFIG_M68030)
+#  define CPU_IS_030 (0)
+#elif defined(CONFIG_M68020) || defined(CONFIG_M68040) || defined(CONFIG_M68060)
+#  define CPU_IS_030 (boot_info.cputype & CPU_68030)
+#else
+#  define CONFIG_M68030_ONLY
+#  define CPU_IS_030 (1)
+#endif
+
+#if !defined(CONFIG_M68040)
+#  define CPU_IS_040 (0)
+#elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68060)
+#  define CPU_IS_040 (boot_info.cputype & CPU_68040)
+#else
+#  define CONFIG_M68040_ONLY
+#  define CPU_IS_040 (1)
+#endif
+
+#if !defined(CONFIG_M68060)
+#  define CPU_IS_060 (0)
+#elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68040)
+#  define CPU_IS_060 (boot_info.cputype & CPU_68060)
+#else
+#  define CONFIG_M68060_ONLY
+#  define CPU_IS_060 (1)
+#endif
+
+#if !defined(CONFIG_M68020) && !defined(CONFIG_M68030)
+#  define CPU_IS_020_OR_030 (0)
+#else
+#  define CONFIG_M68020_OR_M68030
+#  if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+#    define CPU_IS_020_OR_030 (!m68k_is040or060)
+#  else
+#    define CONFIG_M68020_OR_M68030_ONLY
+#    define CPU_IS_020_OR_030 (1)
+#  endif
+#endif
+
+#if !defined(CONFIG_M68040) && !defined(CONFIG_M68060)
+#  define CPU_IS_040_OR_060 (0)
+#else
+#  define CONFIG_M68040_OR_M68060
+#  if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+#    define CPU_IS_040_OR_060 (m68k_is040or060)
+#  else
+#    define CONFIG_M68040_OR_M68060_ONLY
+#    define CPU_IS_040_OR_060 (1)
+#  endif
+#endif
+
+#define CPU_TYPE (boot_info.cputype)
+
+#ifndef __ASSEMBLY__
+#ifdef __KERNEL__
+	/*
+	 * m68k_is040or060 is != 0 for a '040 or higher;
+	 * used numbers are 4 for 68040 and 6 for 68060.
+	 */
+
+extern int m68k_is040or060;
+#endif
+
+struct bootinfo {
+	unsigned long machtype;			/* machine type */
+	unsigned long cputype;			/* system CPU & FPU */
+	struct mem_info memory[NUM_MEMINFO];	/* memory description */
+	int num_memory;				/* # of memory blocks found */
+	unsigned long ramdisk_size;		/* ramdisk size in 1024 byte blocks */
+	unsigned long ramdisk_addr;		/* address of the ram disk in mem */
+	char command_line[CL_SIZE];		/* kernel command line parameters */
+	union {
+		struct bi_Amiga bi_ami; 	/* Amiga specific information */
+		struct bi_Atari bi_ata; 	/* Atari specific information */
+	} bi_un;
+};
+#define bi_amiga bi_un.bi_ami
+#define bi_atari bi_un.bi_ata
+#define bi_mac	 bi_un.bi_mac
+
+extern struct bootinfo
+    boot_info;
+
+#else	/* __ASSEMBLY__ */
+
+BI_machtype	= 0
+BI_cputype	= BI_machtype+4
+BI_memory	= BI_cputype+4
+BI_num_memory	= BI_memory+(MI_sizeof*NUM_MEMINFO)
+BI_ramdisk_size	= BI_num_memory+4
+BI_ramdisk_addr	= BI_ramdisk_size+4
+BI_command_line	= BI_ramdisk_addr+4
+BI_un		= BI_command_line+CL_SIZE
+
+#endif /* __ASSEMBLY__ */
+
+
+/*
+ * Stuff for bootinfo interface versioning
+ *
+ * At the start of kernel code, a 'struct bootversion' is located. bootstrap
+ * checks for a matching version of the interface before booting a kernel, to
+ * avoid user confusion if kernel and bootstrap don't work together :-)
+ *
+ * If incompatible changes are made to the bootinfo interface, the major
+ * number below should be stepped (and the minor reset to 0) for the
+ * appropriate machine. If a change is backward-compatible, the minor should
+ * be stepped. "Backwards-compatible" means that booting will work, but
+ * certain features may not.
+ */
+
+#define BOOTINFOV_MAGIC			0x4249561A	/* 'BIV^Z' */
+#define MK_BI_VERSION(major,minor)	(((major)<<16)+(minor))
+#define BI_VERSION_MAJOR(v)		(((v) >> 16) & 0xffff)
+#define BI_VERSION_MINOR(v)		((v) & 0xffff)
+
+#ifndef __ASSEMBLY__
+
+struct bootversion {
+	unsigned short branch;
+	unsigned long magic;
+	struct {
+		unsigned long machtype;
+		unsigned long version;
+	} machversions[0];
+};
+
+#endif /* __ASSEMBLY__ */
+
+#define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+
+#endif /* _M68K_SETUP_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/string.h linux/include/asm-m68k/string.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/string.h	Sat Mar 30 14:11:50 1996
+++ linux/include/asm-m68k/string.h	Wed Sep 25 10:47:42 1996
@@ -1,6 +1,9 @@
 #ifndef _M68K_STRING_H_
 #define _M68K_STRING_H_
 
+#include <linux/config.h>
+#include <asm/page.h>
+
 #define __HAVE_ARCH_STRCPY
 extern inline char * strcpy(char * dest,const char *src)
 {
@@ -187,14 +190,65 @@
 }
 
 #define __HAVE_ARCH_MEMSET
-extern inline void * memset(void * s,int c,size_t count)
+/*
+ * This is really ugly, but its highly optimizatiable by the
+ * compiler and is meant as compensation for gcc's missing
+ * __builtin_memset(). For the 680[23]0	it might be worth considering
+ * the optimal number of misaligned writes compared to the number of
+ * tests'n'branches needed to align the destination address. The
+ * 680[46]0 doesn't really care due to their copy-back caches.
+ *						10/09/96 - Jes Sorensen
+ */
+extern inline void * __memset_g(void * s, int c, size_t count)
 {
   void *xs = s;
   size_t temp;
 
   if (!count)
     return xs;
+
   c &= 0xff;
+  c |= c << 8;
+  c |= c << 16;
+
+  if (count < 36){
+	  long *ls = s;
+
+	  switch(count){
+	  case 32: case 33: case 34: case 35:
+		  *ls++ = c;
+	  case 28: case 29: case 30: case 31:
+		  *ls++ = c;
+	  case 24: case 25: case 26: case 27:
+		  *ls++ = c;
+	  case 20: case 21: case 22: case 23:
+		  *ls++ = c;
+	  case 16: case 17: case 18: case 19:
+		  *ls++ = c;
+	  case 12: case 13: case 14: case 15:
+		  *ls++ = c;
+	  case 8: case 9: case 10: case 11:
+		  *ls++ = c;
+	  case 4: case 5: case 6: case 7:
+		  *ls++ = c;
+		  break;
+	  default:
+		  break;
+	  }
+	  s = ls;
+	  if (count & 0x02){
+		  short *ss = s;
+		  *ss++ = c;
+		  s = ss;
+	  }
+	  if (count & 0x01){
+		  char *cs = s;
+		  *cs++ = c;
+		  s = cs;
+	  }
+	  return xs;
+  }
+
   if ((long) s & 1)
     {
       char *cs = s;
@@ -202,7 +256,6 @@
       s = cs;
       count--;
     }
-  c |= c << 8;
   if (count > 2 && (long) s & 2)
     {
       short *ss = s;
@@ -214,7 +267,6 @@
   if (temp)
     {
       long *ls = s;
-      c |= c << 16;
       temp--;
       do
 	*ls++ = c;
@@ -235,10 +287,141 @@
   return xs;
 }
 
+/*
+ * __memset_page assumes that data is longword aligned. Most, if not
+ * all, of these page sized memsets are performed on page aligned
+ * areas, thus we do not need to check if the destination is longword
+ * aligned. Of course we suffer a serious performance loss if this is
+ * not the case but I think the risk of this ever happening is
+ * extremely small. We spend a lot of time clearing pages in
+ * get_empty_page() so I think it is worth it anyway. Besides, the
+ * 680[46]0 do not really care about misaligned writes due to their
+ * copy-back cache.
+ *
+ * The optimized case for the 680[46]0 is implemented using the move16
+ * instruction. My tests showed that this implementation is 35-45%
+ * faster than the original implementation using movel, the only
+ * caveat is that the destination address must be 16-byte aligned.
+ *                                            01/09/96 - Jes Sorensen
+ */
+extern inline void * __memset_page(void * s,int c,size_t count)
+{
+  unsigned long data, tmp;
+  void *xs, *sp;
+
+  xs = sp = s;
+
+  c = c & 255;
+  data = c | (c << 8);
+  data |= data << 16;
+
+#if defined(CONFIG_OPTIMIZE_040) || defined(CONFIG_OPTIMIZE_060)
+
+  if (((unsigned long) s) & 0x0f)
+	  memset(s, c, count);
+  else{
+	  *((unsigned long *)(s))++ = data;
+	  *((unsigned long *)(s))++ = data;
+	  *((unsigned long *)(s))++ = data;
+	  *((unsigned long *)(s))++ = data;
+
+	  __asm__ __volatile__("1:\t"
+			       "move16 %2@+,%0@+\n\t"
+			       "subqw  #8,%2\n\t"
+			       "subqw  #8,%2\n\t"
+			       "dbra   %1,1b\n\t"
+			       : "=a" (s), "=d" (tmp)
+			       : "a" (sp), "0" (s), "1" ((count - 16) / 16 - 1)
+			       );
+  }
+
+#else
+  __asm__ __volatile__("1:\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "movel %2,%0@+\n\t"
+		       "dbra  %1,1b\n\t"
+		       : "=a" (s), "=d" (tmp)
+		       : "d" (data), "0" (s), "1" (count / 32 - 1)
+		       );
+#endif
+
+  return xs;
+}
+
+#define __memset_const(s,c,count) \
+((count==PAGE_SIZE) ? \
+  __memset_page((s),(c),(count)) : \
+  __memset_g((s),(c),(count)))
+
+#define memset(s, c, count) \
+(__builtin_constant_p(count) ? \
+ __memset_const((s),(c),(count)) : \
+ memset((s),(c),(count)))
+
 #define __HAVE_ARCH_MEMCPY
+/*
+ * __builtin_memcpy() does not handle page-sized memcpys very well,
+ * thus following the same assumptions as for page-sized memsets, this
+ * function copies page-sized areas using an unrolled loop, without
+ * considering alignment.
+ *
+ * For the 680[46]0 only kernels we use the move16 instruction instead
+ * as it writes through the data-cache, invalidating the cache-lines
+ * touched. In this way we do not use up the entire data-cache (well,
+ * half of it on the 68060) by copying a page. An unrolled loop of two
+ * move16 instructions seem to the fastest. The only caveat is that
+ * both source and destination must be 16-byte aligned, if not we fall
+ * back to the generic memcpy function.  - Jes
+ */
+extern inline void * __memcpy_page(void * to, const void * from, size_t count)
+{
+  unsigned long tmp;
+  void *xto = to;
+
+#if defined(CONFIG_OPTIMIZE_040) || defined(CONFIG_OPTIMIZE_060)
+
+  if (((unsigned long) to | (unsigned long) from) & 0x0f)
+	  return memcpy(to, from, count);
+
+  __asm__ __volatile__("1:\t"
+		       "move16 %1@+,%0@+\n\t"
+		       "move16 %1@+,%0@+\n\t"
+		       "dbra  %2,1b\n\t"
+		       : "=a" (to), "=a" (from), "=d" (tmp)
+		       : "0" (to), "1" (from) , "2" (count / 32 - 1)
+		       );
+#else
+  __asm__ __volatile__("1:\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "movel %1@+,%0@+\n\t"
+		       "dbra  %2,1b\n\t"
+		       : "=a" (to), "=a" (from), "=d" (tmp)
+		       : "0" (to), "1" (from) , "2" (count / 32 - 1)
+		       );
+#endif
+  return xto;
+}
+
+#define __memcpy_const(to, from, n) \
+((n==PAGE_SIZE) ? \
+  __memcpy_page((to),(from),(n)) : \
+  __builtin_memcpy((to),(from),(n)))
+
 #define memcpy(to, from, n) \
 (__builtin_constant_p(n) ? \
- __builtin_memcpy((to),(from),(n)) : \
+ __memcpy_const((to),(from),(n)) : \
  memcpy((to),(from),(n)))
 
 #define __HAVE_ARCH_MEMMOVE
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/system.h	Mon May  6 12:44:32 1996
+++ linux/include/asm-m68k/system.h	Wed Sep 25 10:47:42 1996
@@ -40,13 +40,20 @@
  * to push them onto the stack and read them back right after.
  *
  * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
+ *
+ * Changed 96/09/19 by Andreas Schwab
+ * pass prev in a0, next in a1, offset of tss in d1, and whether
+ * the mm structures are shared in d2 (to avoid atc flushing).
  */
 asmlinkage void resume(void);
 #define switch_to(prev,next) { \
-  register int k __asm__ ("a1") = (int)&((struct task_struct *)0)->tss; \
-  register int n __asm__ ("d1") = (int)next; \
+  register void *_prev __asm__ ("a0") = (prev); \
+  register void *_next __asm__ ("a1") = (next); \
+  register int _tssoff __asm__ ("d1") = (int)&((struct task_struct *)0)->tss; \
+  register char _shared __asm__ ("d2") = ((prev)->mm == (next)->mm); \
   __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) "\n\t" \
-		       : : "a" (k), "d" (n) \
+		       : : "a" (_prev), "a" (_next), "d" (_tssoff), \
+		           "d" (_shared) \
 		       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
 }
 
@@ -74,7 +81,7 @@
 
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
-#if 1
+#ifndef CONFIG_RMW_INSNS
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
   unsigned long tmp, flags;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/unistd.h	Thu May 16 09:05:11 1996
+++ linux/include/asm-m68k/unistd.h	Wed Sep 25 10:47:42 1996
@@ -437,6 +437,10 @@
 {
 	register long retval __asm__ ("d0") = __NR_clone;
 	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+	unsigned short fs;
+
+	fs = get_fs();
+	set_fs (KERNEL_DS);
 
 	__asm__ __volatile__
 	  ("movel %%sp,%%d2\n\t"
@@ -453,6 +457,7 @@
 	     "r" (arg), "a" (fn), "d" (clone_arg)
 	   : "d0", "d2");
 
+	set_fs (fs);
 	return retval;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-m68k/zorro.h linux/include/asm-m68k/zorro.h
--- lx2.0/v2.0.21/linux/include/asm-m68k/zorro.h	Mon May 20 07:54:29 1996
+++ linux/include/asm-m68k/zorro.h	Wed Sep 25 10:47:42 1996
@@ -21,18 +21,27 @@
  * Defined Board Manufacturers
  *
  * Please update arch/m68k/amiga/zorro.c if you make changes here
- * Many IDs were obtained by using ExpName V1.4 ((C) Richard Körber)
- * and by looking at the NetBSD-Amiga kernel source
+ * 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_COMMODORE2       (0x0201)	/* Commodore Germany */
-#define PROD_A2088             (0x01)	/* CBM A2088 Bridgeboard */
+#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 USA */
+#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 */
@@ -45,19 +54,57 @@
 #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_VXL_RAM           (0x44)	/* VXL RAM */
 #define PROD_VXL_30            (0x45)	/* VXL-30 Turbo Board */
+#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_ASDG_DUAL_SERIAL  (0xFF)	/* Dual Serial Card */
+#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 */
@@ -68,20 +115,38 @@
 #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_500RX       (0x09)	/* 500RX/2000 RAM */
+#define PROD_SUPRA_500RX_2     (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_2400MODEM   (0x10)	/* Supra 2400 Modem */
+#define PROD_SUPRA_2400ZIPLUS  (0x10)	/* 2400zi+ Modem */
 
 #define MANUF_CSA              (0x0422)	/* CSA */
 #define PROD_MAGNUM            (0x11)	/* Magnum 40 SCSI Controller */
 #define PROD_12GAUGE           (0x15)	/* 12 Gauge SCSI Controller */
 
+#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 */
-#define PROD_DKB_1240          (0x12)	/* Viper II Turbo Board (DKB 1240) */
+#define MANUF_POWER_COMPUTING  (0x07DC)	/* Power Computing (DKB) */
+#define PROD_DKB_3128          (0x0E)	/* DKB 3128 RAM */
+#define PROD_VIPER_II_COBRA    (0x12)	/* Viper II Turbo Board (DKB Cobra) */
 
 #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 */
@@ -90,10 +155,18 @@
 					   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 */
@@ -101,11 +174,22 @@
 #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_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 */
@@ -113,42 +197,71 @@
 #define MANUF_CHECKPOINT       (0x0807)	/* Checkpoint Technologies */
 #define PROD_SERIAL_SOLUTION   (0x00)	/* Serial Solution */
 
-#define MANUF_GOLEM            (0x0819)	/* Golem */
-#define PROD_GOLEM_SCSI_II     (0x02)	/* Golem SCSI-II Controller */
+#define MANUF_ICD              (0x0817)	/* ICD */
+#define PROD_ADVANTAGE_2000    (0x01)	/* Advantage 2000 SCSI Controller */
 
-#define MANUF_HARDITAL_SYNTHES (0x0817)	/* Hardital Synthesis */
-#define PROD_HARDITAL_SCSI     (0x01)	/* Hardital Synthesis 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_SCSI_AT     (0x05)	/* SCSI/AT Controller */
 
-#define MANUF_HARDITAL2        (0x0820)	/* Hardital Synthesis */
+#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 */
+#define PROD_TANDEM            (0x06)	/* BSC Tandem AT-2008/508 IDE */
 #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_ISDN_MASTER       (0x40)	/* BSC ISDN Master */
+#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_TRUMPCARD_500     (0x30)	/* Trumpcard 500 SCSI Controller */
-#define PROD_TRUMPCARD         (0x34)	/* Trumpcard SCSI Controller */
+#define PROD_GRANDSLAM         (0x04)	/* GrandSlam 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_VECTOR            (0xF3)	/* 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 MANUF_HYDRA_SYSTEMS    (0x0849)	/* Hydra Systems */
 #define PROD_AMIGANET          (0x01)	/* Amiganet Board */
 
-#define MANUF_DIG_MICRONICS    (0x0851)	/* Digital Micronics Inc */
+#define MANUF_SUNRIZE          (0x084F)	/* Sunrize Industries */
+#define PROD_AD516             (0x02)	/* AD516 Audio */
+
+#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 */
@@ -156,52 +269,101 @@
 #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 (RAM) */
+#define PROD_DOMINO_REG        (0x02)	/* Domino Graphics Board (REG) */
 #define PROD_PICASSO_II_RAM    (0x0B)	/* Picasso II Graphics Board */
 #define PROD_PICASSO_II_REG    (0x0C)
+#define PROD_PICASSO_II_REG_2  (0x0D)
 #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_MTEC             (0x0890)	/* MTEC Germany */
 #define PROD_MTEC_68030        (0x03)	/* 68030 Turbo Board */
-#define PROD_MTEC_T1230        (0x20)	/* MTEC T1230/28 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)	/* GVP Spectrum Graphics Board */
+#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 SCSI Controller */
+#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_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_INFORMATION      (0x157C)	/* Information */
+#define PROD_ISDN_ENGINE_I     (0x64)	/* ISDN Engine I */
+
 #define MANUF_VORTEX           (0x2017)	/* Vortex */
-#define PROD_GOLDEN_GATE_386   (0x07)	/* Golden Gate 80386 Board */
+#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_4000SX  (0x01)	/* DataFlyer 4000SX SCSI Controller */
+#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 */
-#define PROD_CYBERSTORM_SCSI   (0x0C)	/* CyberStorm Fast SCSI-II Controller */
+#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 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        (0x19)	/* CyberStorm */
 #define PROD_CYBERVISION       (0x22)	/* CyberVision64 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 MANUF_APOLLO           (0x2222)	/* Apollo */
 #define PROD_AT_APOLLO         (0x22)	/* AT-Apollo */
 #define PROD_APOLLO_TURBO      (0x23)	/* Apollo Turbo Board */
@@ -215,11 +377,24 @@
 #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_FALCON_040        (0xFD)	/* Falcon '040 Turbo Board */
 
+#define MANUF_COMBITEC         (0x6766)	/* Combitec */
+
+#define MANUF_SKI              (0x8000)	/* SKI Peripherals */
+#define PROD_SKI_SCSI_SERIAL   (0x80)	/* SCSI / Dual Serial */
 
-/* Illegal Manufacturer IDs. These do NOT appear in amiga/zorro.c! */
+#define MANUF_CAMERON          (0xAA01)	/* Cameron */
+#define PROD_CAMERON_SCANNER   (0x10)	/* Scanner Interface */
+
+#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 */
@@ -227,14 +402,21 @@
 #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 GVPEPCMASK
+ * product code' (epc). The epc has to be and'ed with the GVP_PRODMASK
  * before the identification.
  */
 
-#define GVP_EPCMASK (0xf8)
+#define GVP_PRODMASK    (0xf8)
+#define GVP_SCSICLKMASK (0x01)
 
 enum GVP_ident {
   GVP_GFORCE_040      = 0x20,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-mips/fcntl.h	Tue Apr 30 13:09:45 1996
+++ linux/include/asm-mips/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -49,12 +49,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 typedef struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-mips/floppy.h linux/include/asm-mips/floppy.h
--- lx2.0/v2.0.21/linux/include/asm-mips/floppy.h	Sun Apr 28 18:47:40 1996
+++ linux/include/asm-mips/floppy.h	Sat Sep 28 22:05:41 1996
@@ -25,7 +25,7 @@
 #define fd_free_dma()			feature->fd_free_dma()
 #define fd_clear_dma_ff()		feature->fd_clear_dma_ff()
 #define fd_set_dma_mode(mode)		feature->fd_set_dma_mode(mode)
-#define fd_set_dma_addr(addr)		feature->fd_set_dma_addr(addr)
+#define fd_set_dma_addr(addr)		feature->fd_set_dma_addr(virt_to_bus(addr))
 #define fd_set_dma_count(count)		feature->fd_set_dma_count(count)
 #define fd_get_dma_residue()		feature->fd_get_dma_residue()
 #define fd_enable_irq()			feature->fd_enable_irq()
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-ppc/fcntl.h	Tue Apr 30 13:09:45 1996
+++ linux/include/asm-ppc/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -48,12 +48,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-ppc/floppy.h linux/include/asm-ppc/floppy.h
--- lx2.0/v2.0.21/linux/include/asm-ppc/floppy.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/floppy.h	Sat Sep 28 22:05:42 1996
@@ -19,7 +19,7 @@
 #define fd_free_dma()           free_dma(FLOPPY_DMA)
 #define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
 #define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
-#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,addr)
+#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,virt_to_bus(addr))
 #define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h
--- lx2.0/v2.0.21/linux/include/asm-sparc/fcntl.h	Tue Apr 30 13:09:45 1996
+++ linux/include/asm-sparc/fcntl.h	Sun Sep 22 09:41:32 1996
@@ -48,12 +48,6 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
-#ifdef __KERNEL__
-#define F_POSIX		1
-#define F_FLOCK		2
-#define F_BROKEN	4	/* broken flock() emulation */
-#endif /* __KERNEL__ */
-
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/fs.h linux/include/linux/fs.h
--- lx2.0/v2.0.21/linux/include/linux/fs.h	Fri Sep 20 17:00:36 1996
+++ linux/include/linux/fs.h	Mon Sep 30 11:19:00 1996
@@ -336,16 +336,22 @@
 	void *private_data;	/* needed for tty driver, and maybe others */
 };
 
+#define FL_POSIX	1
+#define FL_FLOCK	2
+#define FL_BROKEN	4	/* broken flock() emulation */
+#define FL_ACCESS	8	/* for processes suspended by mandatory locking */
+
 struct file_lock {
 	struct file_lock *fl_next;	/* singly linked list for this inode  */
 	struct file_lock *fl_nextlink;	/* doubly linked list of all locks */
 	struct file_lock *fl_prevlink;	/* used to simplify lock removal */
-	struct file_lock *fl_block;
+	struct file_lock *fl_nextblock; /* circular list of blocked processes */
+	struct file_lock *fl_prevblock;
 	struct task_struct *fl_owner;
 	struct wait_queue *fl_wait;
 	struct file *fl_file;
-	char fl_flags;
-	char fl_type;
+	unsigned char fl_flags;
+	unsigned char fl_type;
 	off_t fl_start;
 	off_t fl_end;
 };
@@ -455,9 +461,9 @@
 typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
 	
 struct file_operations {
-	int (*lseek) (struct inode *, struct file *, off_t, int);
-	int (*read) (struct inode *, struct file *, char *, int);
-	int (*write) (struct inode *, struct file *, const char *, int);
+	long long (*llseek) (struct inode *, struct file *, long long, int);
+	long (*read) (struct inode *, struct file *, char *, unsigned long);
+	long (*write) (struct inode *, struct file *, const char *, unsigned long);
 	int (*readdir) (struct inode *, struct file *, void *, filldir_t);
 	int (*select) (struct inode *, struct file *, int, select_table *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
@@ -652,10 +658,11 @@
 extern struct buffer_head * breada(kdev_t dev,int block, int size, 
 				   unsigned int pos, unsigned int filesize);
 
+extern int brw_page(int, struct page *, kdev_t, int [], int, int);
+
 extern int generic_readpage(struct inode *, struct page *);
-extern int generic_file_read(struct inode *, struct file *, char *, int);
 extern int generic_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
-extern int brw_page(int, struct page *, kdev_t, int [], int, int);
+extern long generic_file_read(struct inode *, struct file *, char *, unsigned long);
 
 extern void put_super(kdev_t dev);
 unsigned long generate_cluster(kdev_t dev, int b[], int size);
@@ -669,12 +676,12 @@
 extern int change_root(kdev_t new_root_dev,const char *put_old);
 #endif
 
-extern int char_read(struct inode *, struct file *, char *, int);
-extern int block_read(struct inode *, struct file *, char *, int);
+extern long char_read(struct inode *, struct file *, char *, unsigned long);
+extern long block_read(struct inode *, struct file *, char *, unsigned long);
 extern int read_ahead[];
 
-extern int char_write(struct inode *, struct file *, const char *, int);
-extern int block_write(struct inode *, struct file *, const char *, int);
+extern long char_write(struct inode *, struct file *, const char *, unsigned long);
+extern long block_write(struct inode *, struct file *, const char *, unsigned long);
 
 extern int block_fsync(struct inode *, struct file *);
 extern int file_fsync(struct inode *, struct file *);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/ldt.h linux/include/linux/ldt.h
--- lx2.0/v2.0.21/linux/include/linux/ldt.h	Tue Nov 21 08:34:54 1995
+++ linux/include/linux/ldt.h	Thu Jan  1 02:00:00 1970
@@ -1,29 +0,0 @@
-/*
- * ldt.h
- *
- * Definitions of structures used with the modify_ldt system call.
- */
-#ifndef _LINUX_LDT_H
-#define _LINUX_LDT_H
-
-/* Maximum number of LDT entries supported. */
-#define LDT_ENTRIES	8192
-/* The size of each LDT entry. */
-#define LDT_ENTRY_SIZE	8
-
-struct modify_ldt_ldt_s {
-	unsigned int  entry_number;
-	unsigned long base_addr;
-	unsigned int  limit;
-	unsigned int  seg_32bit:1;
-	unsigned int  contents:2;
-	unsigned int  read_exec_only:1;
-	unsigned int  limit_in_pages:1;
-	unsigned int  seg_not_present:1;
-};
-
-#define MODIFY_LDT_CONTENTS_DATA	0
-#define MODIFY_LDT_CONTENTS_STACK	1
-#define MODIFY_LDT_CONTENTS_CODE	2
-
-#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/mm.h linux/include/linux/mm.h
--- lx2.0/v2.0.21/linux/include/linux/mm.h	Wed Sep 11 17:57:18 1996
+++ linux/include/linux/mm.h	Mon Sep 30 11:19:00 1996
@@ -9,7 +9,8 @@
 
 #include <linux/string.h>
 
-extern unsigned long high_memory;
+extern unsigned long max_mapnr;
+extern void * high_memory;
 
 #include <asm/page.h>
 #include <asm/atomic.h>
@@ -274,13 +275,6 @@
 extern void show_mem(void);
 extern void oom(struct task_struct * tsk);
 extern void si_meminfo(struct sysinfo * val);
-
-/* vmalloc.c */
-
-extern void * vmalloc(unsigned long size);
-extern void * vremap(unsigned long offset, unsigned long size);
-extern void vfree(void * addr);
-extern int vread(char *buf, char *addr, int count);
 
 /* mmap.c */
 extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- lx2.0/v2.0.21/linux/include/linux/msdos_fs.h	Thu Jul 25 20:30:08 1996
+++ linux/include/linux/msdos_fs.h	Mon Sep 30 11:22:48 1996
@@ -221,8 +221,8 @@
 /* file.c */
 extern struct inode_operations fat_file_inode_operations;
 extern struct inode_operations fat_file_inode_operations_1024;
-extern int fat_file_read(struct inode *, struct file *, char *, int);
-extern int fat_file_write(struct inode *, struct file *, const char *, int);
+extern long fat_file_read(struct inode *, struct file *, char *, unsigned long);
+extern long fat_file_write(struct inode *, struct file *, const char *, unsigned long);
 extern void fat_truncate(struct inode *inode);
 
 /* mmap.c */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- lx2.0/v2.0.21/linux/include/linux/sysv_fs.h	Thu Jul 25 20:31:45 1996
+++ linux/include/linux/sysv_fs.h	Mon Sep 30 11:24:25 1996
@@ -385,7 +385,7 @@
 
 extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
 extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
-extern int sysv_file_read(struct inode *, struct file *, char *, int);
+extern long sysv_file_read(struct inode *, struct file *, char *, unsigned long);
 
 extern void sysv_truncate(struct inode *);
 extern void sysv_put_super(struct super_block *);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- lx2.0/v2.0.21/linux/include/linux/umsdos_fs.p	Wed Jul  3 16:39:14 1996
+++ linux/include/linux/umsdos_fs.p	Mon Sep 30 11:09:13 1996
@@ -1,10 +1,10 @@
 /* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
 /* dir.c 22/06/95 00.22.12 */
-int UMSDOS_dir_read (struct inode *inode,
+long UMSDOS_dir_read (struct inode *inode,
 	 struct file *filp,
 	 char *buf,
-	 int count);
+	 unsigned long count);
 void umsdos_lookup_patch (struct inode *dir,
 	 struct inode *inode,
 	 struct umsdos_dirent *entry,
@@ -20,22 +20,22 @@
 	 struct inode **result);
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
 /* emd.c 22/06/95 00.22.04 */
-int umsdos_file_read_kmem (struct inode *inode,
+long umsdos_file_read_kmem (struct inode *inode,
 	 struct file *filp,
 	 char *buf,
-	 int count);
-int umsdos_file_write_kmem (struct inode *inode,
+	 unsigned long count);
+long umsdos_file_write_kmem (struct inode *inode,
 	 struct file *filp,
 	 const char *buf,
-	 int count);
-int umsdos_emd_dir_write (struct inode *emd_dir,
+	 unsigned long count);
+long umsdos_emd_dir_write (struct inode *emd_dir,
 	 struct file *filp,
 	 char *buf,
-	 int count);
-int umsdos_emd_dir_read (struct inode *emd_dir,
+	 unsigned long count);
+long umsdos_emd_dir_read (struct inode *emd_dir,
 	 struct file *filp,
 	 char *buf,
-	 int count);
+	 unsigned long count);
 struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat);
 int umsdos_emd_dir_readentry (struct inode *emd_dir,
 	 struct file *filp,
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/vmalloc.h linux/include/linux/vmalloc.h
--- lx2.0/v2.0.21/linux/include/linux/vmalloc.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/vmalloc.h	Mon Sep 30 11:19:11 1996
@@ -0,0 +1,32 @@
+#ifndef __LINUX_VMALLOC_H
+#define __LINUX_VMALLOC_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+
+struct vm_struct {
+	unsigned long flags;
+	void * addr;
+	unsigned long size;
+	struct vm_struct * next;
+};
+
+struct vm_struct * get_vm_area(unsigned long size);
+void vfree(void * addr);
+void * vmalloc(unsigned long size);
+int vread(char *buf, char *addr, int count);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+}
+
+#endif
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/linux/xd.h linux/include/linux/xd.h
--- lx2.0/v2.0.21/linux/include/linux/xd.h	Fri Mar  1 07:50:56 1996
+++ linux/include/linux/xd.h	Thu Jan  1 02:00:00 1970
@@ -1,138 +0,0 @@
-#ifndef _LINUX_XD_H
-#define _LINUX_XD_H
-
-/*
- * This file contains the definitions for the IO ports and errors etc. for XT hard disk controllers (at least the DTC 5150X).
- *
- * Author: Pat Mackinlay, pat@it.com.au
- * Date: 29/09/92
- *
- * Revised: 01/01/93, ...
- *
- * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
- * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
- */
-
-/* XT hard disk controller registers */
-#define XD_DATA		(xd_iobase + 0x00)	/* data RW register */
-#define XD_RESET	(xd_iobase + 0x01)	/* reset WO register */
-#define XD_STATUS	(xd_iobase + 0x01)	/* status RO register */
-#define XD_SELECT	(xd_iobase + 0x02)	/* select WO register */
-#define XD_JUMPER	(xd_iobase + 0x02)	/* jumper RO register */
-#define XD_CONTROL	(xd_iobase + 0x03)	/* DMAE/INTE WO register */
-#define XD_RESERVED	(xd_iobase + 0x03)	/* reserved */
-
-/* XT hard disk controller commands (incomplete list) */
-#define CMD_TESTREADY	0x00	/* test drive ready */
-#define CMD_RECALIBRATE	0x01	/* recalibrate drive */
-#define CMD_SENSE	0x03	/* request sense */
-#define CMD_FORMATDRV	0x04	/* format drive */
-#define CMD_VERIFY	0x05	/* read verify */
-#define CMD_FORMATTRK	0x06	/* format track */
-#define CMD_FORMATBAD	0x07	/* format bad track */
-#define CMD_READ	0x08	/* read */
-#define CMD_WRITE	0x0A	/* write */
-#define CMD_SEEK	0x0B	/* seek */
-
-/* Controller specific commands */
-#define CMD_DTCSETPARAM	0x0C	/* set drive parameters (DTC 5150X only?) */
-#define CMD_DTCGETECC	0x0D	/* get ecc error length (DTC 5150X only?) */
-#define CMD_DTCREADBUF	0x0E	/* read sector buffer (DTC 5150X only?) */
-#define CMD_DTCWRITEBUF 0x0F	/* write sector buffer (DTC 5150X only?) */
-#define CMD_DTCREMAPTRK	0x11	/* assign alternate track (DTC 5150X only?) */
-#define CMD_DTCGETPARAM	0xFB	/* get drive parameters (DTC 5150X only?) */
-#define CMD_DTCSETSTEP	0xFC	/* set step rate (DTC 5150X only?) */
-#define CMD_DTCSETGEOM	0xFE	/* set geometry data (DTC 5150X only?) */
-#define CMD_DTCGETGEOM	0xFF	/* get geometry data (DTC 5150X only?) */
-#define CMD_ST11GETGEOM 0xF8	/* get geometry data (Seagate ST11R/M only?) */
-#define CMD_WDSETPARAM	0x0C	/* set drive parameters (WD 1004A27X only?) */
-
-/* Bits for command status byte */
-#define CSB_ERROR	0x02	/* error */
-#define CSB_LUN		0x20	/* logical Unit Number */
-
-/* XT hard disk controller status bits */
-#define STAT_READY	0x01	/* controller is ready */
-#define STAT_INPUT	0x02	/* data flowing from controller to host */
-#define STAT_COMMAND	0x04	/* controller in command phase */
-#define STAT_SELECT	0x08	/* controller is selected */
-#define STAT_REQUEST	0x10	/* controller requesting data */
-#define STAT_INTERRUPT	0x20	/* controller requesting interrupt */
-
-/* XT hard disk controller control bits */
-#define PIO_MODE	0x00	/* control bits to set for PIO */
-#define DMA_MODE	0x03	/* control bits to set for DMA & interrupt */
-
-#define XD_MAXDRIVES	2	/* maximum 2 drives */
-#define XD_TIMEOUT	HZ	/* 1 second timeout */
-#define XD_RETRIES	4	/* maximum 4 retries */
-
-#undef DEBUG			/* define for debugging output */
-
-#ifdef DEBUG
-	#define DEBUG_STARTUP	/* debug driver initialisation */
-	#define DEBUG_OVERRIDE	/* debug override geometry detection */
-	#define DEBUG_READWRITE	/* debug each read/write command */
-	#define DEBUG_OTHER	/* debug misc. interrupt/DMA stuff */
-	#define DEBUG_COMMAND	/* debug each controller command */
-#endif /* DEBUG */
-
-/* this structure defines the XT drives and their types */
-typedef struct {
-	u_char heads;
-	u_short cylinders;
-	u_char sectors;
-	u_char control;
-} XD_INFO;
-
-#define	HDIO_GETGEO	0x0301		/* get drive geometry */
-
-/* this structure is returned to the HDIO_GETGEO ioctl */
-typedef struct {
-	u_char heads;
-	u_char sectors;
-	u_short cylinders;
-	u_long start;
-} XD_GEOMETRY;
-
-/* this structure defines a ROM BIOS signature */
-typedef struct {
-	u_long offset;
-	const char *string;
-	void (*init_controller)(u_char *address);
-	void (*init_drive)(u_char drive);
-	const char *name;
-} XD_SIGNATURE;
-
-void xd_setup (char *command,int *integers);
-static u_char xd_detect (u_char *controller,u_char **address);
-static u_char xd_initdrives (void (*init_drive)(u_char drive));
-static void xd_geninit (struct gendisk *);
-
-static int xd_open (struct inode *inode,struct file *file);
-static void do_xd_request (void);
-static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
-static void xd_release (struct inode *inode,struct file *file);
-static int xd_reread_partitions (kdev_t dev);
-static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
-static void xd_recalibrate (u_char drive);
-
-static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
-static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
-static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
-static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
-
-/* card specific setup and geometry gathering code */
-static void xd_dtc_init_controller (u_char *address);
-static void xd_dtc_init_drive (u_char drive);
-static void xd_wd_init_controller (u_char *address);
-static void xd_wd_init_drive (u_char drive);
-static void xd_seagate_init_controller (u_char *address);
-static void xd_seagate_init_drive (u_char drive);
-static void xd_omti_init_controller (u_char *address);
-static void xd_omti_init_drive (u_char drive);
-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);
-static void xd_override_init_drive (u_char drive);
-
-#endif /* _LINUX_XD_H */
diff -u --recursive --new-file lx2.0/v2.0.21/linux/include/net/ipx.h linux/include/net/ipx.h
--- lx2.0/v2.0.21/linux/include/net/ipx.h	Thu Jul 25 20:28:50 1996
+++ linux/include/net/ipx.h	Mon Sep 30 11:21:33 1996
@@ -28,9 +28,9 @@
 
 typedef struct ipx_packet
 {
-	unsigned short	ipx_checksum;
+	unsigned short	ipx_checksum __attribute__ ((packed));
 #define IPX_NO_CHECKSUM	0xFFFF
-	unsigned short  ipx_pktsize;
+	unsigned short  ipx_pktsize __attribute__ ((packed));
 	unsigned char   ipx_tctrl;
 	unsigned char   ipx_type;
 #define IPX_TYPE_UNKNOWN	0x00
diff -u --recursive --new-file lx2.0/v2.0.21/linux/init/main.c linux/init/main.c
--- lx2.0/v2.0.21/linux/init/main.c	Wed Sep 11 17:57:18 1996
+++ linux/init/main.c	Mon Sep 23 13:31:03 1996
@@ -98,6 +98,7 @@
 extern void ppa_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
+extern void reboot_setup(char *str, int *ints);
 #ifdef CONFIG_CDU31A
 extern void cdu31a_setup(char *str, int *ints);
 #endif CONFIG_CDU31A
@@ -268,6 +269,7 @@
 #ifdef CONFIG_BUGi386
 	{ "no-hlt", no_halt },
 	{ "no387", no_387 },
+	{ "reboot=", reboot_setup },
 #endif
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
diff -u --recursive --new-file lx2.0/v2.0.21/linux/kernel/fork.c linux/kernel/fork.c
--- lx2.0/v2.0.21/linux/kernel/fork.c	Sun Sep  1 09:15:34 1996
+++ linux/kernel/fork.c	Wed Sep 25 12:51:59 1996
@@ -19,7 +19,6 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
 #include <linux/smp.h>
 
 #include <asm/segment.h>
@@ -100,12 +99,12 @@
 			mpnt->vm_next_share = tmp;
 			tmp->vm_prev_share = mpnt;
 		}
-		if (tmp->vm_ops && tmp->vm_ops->open)
-			tmp->vm_ops->open(tmp);
 		if (copy_page_range(mm, current->mm, tmp)) {
 			exit_mmap(mm);
 			return -ENOMEM;
 		}
+		if (tmp->vm_ops && tmp->vm_ops->open)
+			tmp->vm_ops->open(tmp);
 		*p = tmp;
 		p = &tmp->vm_next;
 	}
diff -u --recursive --new-file lx2.0/v2.0.21/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- lx2.0/v2.0.21/linux/kernel/ksyms.c	Sun Sep 15 10:34:18 1996
+++ linux/kernel/ksyms.c	Thu Sep 26 09:17:27 1996
@@ -19,6 +19,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/ptrace.h>
 #include <linux/sys.h>
 #include <linux/utsname.h>
@@ -129,10 +130,10 @@
 	X(kmalloc),
 	X(kfree),
 	X(vmalloc),
-	X(vremap),
 	X(vfree),
  	X(mem_map),
  	X(remap_page_range),
+	X(max_mapnr),
 	X(high_memory),
 	X(update_vm_cache),
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/kernel/module.c linux/kernel/module.c
--- lx2.0/v2.0.21/linux/kernel/module.c	Tue May 21 12:00:30 1996
+++ linux/kernel/module.c	Wed Sep 25 12:16:12 1996
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/config.h>
 /*
  * Originally by Anonymous (as far as I know...)
diff -u --recursive --new-file lx2.0/v2.0.21/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- lx2.0/v2.0.21/linux/kernel/sysctl.c	Fri Jun  7 15:45:21 1996
+++ linux/kernel/sysctl.c	Sat Sep 28 23:04:13 1996
@@ -46,10 +46,10 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int proc_readsys(struct inode * inode, struct file * file,
-			char * buf, int count);
-static int proc_writesys(struct inode * inode, struct file * file,
-			 const char * buf, int count);
+static long proc_readsys(struct inode * inode, struct file * file,
+			char * buf, unsigned long count);
+static long proc_writesys(struct inode * inode, struct file * file,
+			 const char * buf, unsigned long count);
 static int proc_sys_permission(struct inode *, int);
 
 struct file_operations proc_sys_file_operations =
@@ -456,13 +456,14 @@
 }
 
 
-static int do_rw_proc(int write, struct inode * inode, struct file * file,
-		      char * buf, int count)
+static long do_rw_proc(int write, struct inode * inode, struct file * file,
+		      char * buf, unsigned long count)
 {
-	int error, op;
+	int op;
 	struct proc_dir_entry *de;
 	struct ctl_table *table;
 	size_t res;
+	long error;
 	
 	error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
 	if (error)
@@ -485,14 +486,14 @@
 	return res;
 }
 
-static int proc_readsys(struct inode * inode, struct file * file,
-			char * buf, int count)
+static long proc_readsys(struct inode * inode, struct file * file,
+			char * buf, unsigned long count)
 {
 	return do_rw_proc(0, inode, file, buf, count);
 }
 
-static int proc_writesys(struct inode * inode, struct file * file,
-			 const char * buf, int count)
+static long proc_writesys(struct inode * inode, struct file * file,
+			 const char * buf, unsigned long count)
 {
 	return do_rw_proc(1, inode, file, (char *) buf, count);
 }
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/filemap.c linux/mm/filemap.c
--- lx2.0/v2.0.21/linux/mm/filemap.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/filemap.c	Sat Sep 28 23:20:18 1996
@@ -129,7 +129,7 @@
 {
 	static int clock = 0;
 	struct page * page;
-	unsigned long limit = MAP_NR(high_memory);
+	unsigned long limit = max_mapnr;
 	struct buffer_head *tmp, *bh;
 	int count_max, count_min;
 
@@ -566,7 +566,8 @@
  * of the logic when it comes to error handling etc.
  */
 
-int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+long generic_file_read(struct inode * inode, struct file * filp,
+	char * buf, unsigned long count)
 {
 	int error, read;
 	unsigned long pos, ppos, page_cache;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- lx2.0/v2.0.21/linux/mm/kmalloc.c	Sat Jun  8 18:12:33 1996
+++ linux/mm/kmalloc.c	Fri Sep 27 11:45:16 1996
@@ -405,7 +405,7 @@
 		goto bad_order;
 	ptr->bh_flags = MF_FREE;	/* As of now this block is officially free */
 #ifdef SADISTIC_KMALLOC
-	memset(ptr+1, 0xe0, ptr->bh_length);
+	memset(ptr+1, 0x0e, ptr->bh_length);
 #endif
 	save_flags(flags);
 	cli();
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/memory.c linux/mm/memory.c
--- lx2.0/v2.0.21/linux/mm/memory.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/memory.c	Wed Sep 25 12:27:40 1996
@@ -50,7 +50,8 @@
 #include <asm/pgtable.h>
 #include <asm/string.h>
 
-unsigned long high_memory = 0;
+unsigned long max_mapnr = 0;
+void * high_memory = NULL;
 
 /*
  * We special-case the C-O-W ZERO_PAGE, because it's such
@@ -191,7 +192,7 @@
 		return;
 	}
 	page_nr = MAP_NR(pte_page(pte));
-	if (page_nr >= MAP_NR(high_memory) || PageReserved(mem_map+page_nr)) {
+	if (page_nr >= max_mapnr || PageReserved(mem_map+page_nr)) {
 		set_pte(new_pte, pte);
 		return;
 	}
@@ -302,7 +303,7 @@
 {
 	if (pte_present(page)) {
 		unsigned long addr = pte_page(page);
-		if (addr >= high_memory || PageReserved(mem_map+MAP_NR(addr)))
+		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
 			return;
 		free_page(addr);
 		if (current->mm->rss <= 0)
@@ -462,7 +463,7 @@
  * in null mappings (currently treated as "copy-on-access")
  */
 static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot)
+	unsigned long phys_addr, pgprot_t prot)
 {
 	unsigned long end;
 
@@ -471,19 +472,22 @@
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
 	do {
+		unsigned long mapnr;
 		pte_t oldpage = *pte;
 		pte_clear(pte);
-		if (offset >= high_memory || PageReserved(mem_map+MAP_NR(offset)))
- 			set_pte(pte, mk_pte(offset, prot));
+
+		mapnr = MAP_NR(__va(phys_addr));
+		if (mapnr >= max_mapnr || PageReserved(mem_map+mapnr))
+ 			set_pte(pte, mk_pte_phys(phys_addr, prot));
 		forget_pte(oldpage);
 		address += PAGE_SIZE;
-		offset += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
 		pte++;
 	} while (address < end);
 }
 
 static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot)
+	unsigned long phys_addr, pgprot_t prot)
 {
 	unsigned long end;
 
@@ -491,26 +495,26 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
-	offset -= address;
+	phys_addr -= address;
 	do {
 		pte_t * pte = pte_alloc(pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		remap_pte_range(pte, address, end - address, address + offset, prot);
+		remap_pte_range(pte, address, end - address, address + phys_addr, prot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
 	return 0;
 }
 
-int remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot)
+int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
 
-	offset -= from;
+	phys_addr -= from;
 	dir = pgd_offset(current->mm, from);
 	flush_cache_range(current->mm, beg, end);
 	while (from < end) {
@@ -518,7 +522,7 @@
 		error = -ENOMEM;
 		if (!pmd)
 			break;
-		error = remap_pmd_range(pmd, from, end - from, offset + from, prot);
+		error = remap_pmd_range(pmd, from, end - from, phys_addr + from, prot);
 		if (error)
 			break;
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
@@ -551,7 +555,7 @@
 	pmd_t * pmd;
 	pte_t * pte;
 
-	if (page >= high_memory)
+	if (MAP_NR(page) >= max_mapnr)
 		printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address);
 	if (mem_map[MAP_NR(page)].count != 1)
 		printk("mem_map disagrees with %08lx at %08lx\n",page,address);
@@ -622,7 +626,7 @@
 	if (pte_write(pte))
 		goto end_wp_page;
 	old_page = pte_page(pte);
-	if (old_page >= high_memory)
+	if (MAP_NR(old_page) >= max_mapnr)
 		goto bad_wp_page;
 	tsk->min_flt++;
 	/*
@@ -787,7 +791,7 @@
 	flush_cache_page(vma, address);
 	address &= ~PAGE_MASK;
 	address += pte_page(pte);
-	if (address >= high_memory)
+	if (MAP_NR(address) >= max_mapnr)
 		return;
 	memset((void *) address, 0, PAGE_SIZE - (address & ~PAGE_MASK));
 	flush_page_to_ram(pte_page(pte));
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/mlock.c linux/mm/mlock.c
--- lx2.0/v2.0.21/linux/mm/mlock.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/mlock.c	Mon Sep 23 14:38:29 1996
@@ -202,7 +202,7 @@
 
 	/* we may lock at most half of physical memory... */
 	/* (this check is pretty bogus, but doesn't hurt) */
-	if (locked > MAP_NR(high_memory)/2)
+	if (locked > max_mapnr/2)
 		return -ENOMEM;
 
 	return do_mlock(start, len, 1);
@@ -259,7 +259,7 @@
 
 	/* we may lock at most half of physical memory... */
 	/* (this check is pretty bogus, but doesn't hurt) */
-	if (current->mm->total_vm > MAP_NR(high_memory)/2)
+	if (current->mm->total_vm > max_mapnr/2)
 		return -ENOMEM;
 
 	return do_mlockall(flags);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/mmap.c linux/mm/mmap.c
--- lx2.0/v2.0.21/linux/mm/mmap.c	Wed Sep 11 17:57:19 1996
+++ linux/mm/mmap.c	Mon Sep 23 14:38:29 1996
@@ -58,7 +58,7 @@
 	freepages >>= 1;
 	freepages += nr_free_pages;
 	freepages += nr_swap_pages;
-	freepages -= MAP_NR(high_memory) >> 4;
+	freepages -= max_mapnr >> 4;
 	return freepages > pages;
 }
 
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- lx2.0/v2.0.21/linux/mm/page_alloc.c	Sat Aug 17 21:19:29 1996
+++ linux/mm/page_alloc.c	Mon Sep 23 14:38:29 1996
@@ -135,7 +135,7 @@
 {
 	unsigned long map_nr = MAP_NR(addr);
 
-	if (map_nr < MAP_NR(high_memory)) {
+	if (map_nr < max_mapnr) {
 		mem_map_t * map = mem_map + map_nr;
 		if (PageReserved(map))
 			return;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/swapfile.c linux/mm/swapfile.c
--- lx2.0/v2.0.21/linux/mm/swapfile.c	Tue Jun 11 13:00:11 1996
+++ linux/mm/swapfile.c	Wed Sep 25 12:16:34 1996
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/swapctl.h>
 #include <linux/blkdev.h> /* for blk_size */
+#include <linux/vmalloc.h>
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -170,7 +171,7 @@
 		return 0;
 	if (pte_present(pte)) {
 		unsigned long page_nr = MAP_NR(pte_page(pte));
-		if (page_nr >= MAP_NR(high_memory))
+		if (page_nr >= max_mapnr)
 			return 0;
 		if (!in_swap_cache(page_nr))
 			return 0;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- lx2.0/v2.0.21/linux/mm/vmalloc.c	Mon Aug  5 10:13:55 1996
+++ linux/mm/vmalloc.c	Wed Sep 25 14:33:57 1996
@@ -4,40 +4,14 @@
  *  Copyright (C) 1993  Linus Torvalds
  */
 
-#include <asm/system.h>
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
 #include <linux/malloc.h>
-#include <linux/mm.h>
+#include <linux/vmalloc.h>
 
 #include <asm/segment.h>
-#include <asm/pgtable.h>
-
-struct vm_struct {
-	unsigned long flags;
-	void * addr;
-	unsigned long size;
-	struct vm_struct * next;
-};
+#include <asm/system.h>
 
 static struct vm_struct * vmlist = NULL;
 
-static inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-}
-
 static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
 {
 	pte_t * pte;
@@ -172,69 +146,7 @@
 	return 0;
 }
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long offset)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		if (!pte_none(*pte))
-			printk("remap_area_pte: page already exists\n");
-		set_pte(pte, mk_pte(offset, PAGE_KERNEL));
-		address += PAGE_SIZE;
-		offset += PAGE_SIZE;
-		pte++;
-	} while (address < end);
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	offset -= address;
-	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		remap_area_pte(pte, address, end - address, address + offset);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-	return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long offset, unsigned long size)
-{
-	pgd_t * dir;
-	unsigned long end = address + size;
-
-	offset -= address;
-	dir = pgd_offset(&init_mm, address);
-	flush_cache_all();
-	while (address < end) {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
-		if (!pmd)
-			return -ENOMEM;
-		if (remap_area_pmd(pmd, address, end - address, offset + address))
-			return -ENOMEM;
-		set_pgdir(address, *dir);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	}
-	flush_tlb_all();
-	return 0;
-}
-
-static struct vm_struct * get_vm_area(unsigned long size)
+struct vm_struct * get_vm_area(unsigned long size)
 {
 	void *addr;
 	struct vm_struct **p, *tmp, *area;
@@ -283,7 +195,7 @@
 	struct vm_struct *area;
 
 	size = PAGE_ALIGN(size);
-	if (!size || size > (MAP_NR(high_memory) << PAGE_SHIFT))
+	if (!size || size > (max_mapnr << PAGE_SHIFT))
 		return NULL;
 	area = get_vm_area(size);
 	if (!area)
@@ -296,34 +208,6 @@
 	return addr;
 }
 
-/*
- * Remap an arbitrary physical address space into the kernel virtual
- * address space. Needed when the kernel wants to access high addresses
- * directly.
- */
-void * vremap(unsigned long offset, unsigned long size)
-{
-	void * addr;
-	struct vm_struct * area;
-
-	if (MAP_NR(offset) < MAP_NR(high_memory))
-		return NULL;
-	if (offset & ~PAGE_MASK)
-		return NULL;
-	size = PAGE_ALIGN(size);
-	if (!size || size > offset + size)
-		return NULL;
-	area = get_vm_area(size);
-	if (!area)
-		return NULL;
-	addr = area->addr;
-	if (remap_area_pages(VMALLOC_VMADDR(addr), offset, size)) {
-		vfree(addr);
-		return NULL;
-	}
-	return addr;
-}
-
 int vread(char *buf, char *addr, int count)
 {
 	struct vm_struct **p, *tmp;
@@ -335,7 +219,10 @@
 		while (addr < vaddr) {
 			if (count == 0)
 				goto finished;
-			put_user('\0', buf++), addr++, count--;
+			put_user('\0', buf);
+			buf++;
+			addr++;
+			count--;
 		}
 		n = tmp->size - PAGE_SIZE;
 		if (addr > vaddr)
@@ -343,7 +230,10 @@
 		while (--n >= 0) {
 			if (count == 0)
 				goto finished;
-			put_user(*addr++, buf++), count--;
+			put_user(*addr, buf);
+			buf++;
+			addr++;
+			count--;
 		}
 	}
 finished:
diff -u --recursive --new-file lx2.0/v2.0.21/linux/mm/vmscan.c linux/mm/vmscan.c
--- lx2.0/v2.0.21/linux/mm/vmscan.c	Sun Sep 15 10:34:18 1996
+++ linux/mm/vmscan.c	Mon Sep 23 14:38:29 1996
@@ -79,7 +79,7 @@
 	if (!pte_present(pte))
 		return 0;
 	page = pte_page(pte);
-	if (MAP_NR(page) >= MAP_NR(high_memory))
+	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 
 	page_map = mem_map + MAP_NR(page);
diff -u --recursive --new-file lx2.0/v2.0.21/linux/net/bridge/br.c linux/net/bridge/br.c
--- lx2.0/v2.0.21/linux/net/bridge/br.c	Fri Jul 19 08:24:05 1996
+++ linux/net/bridge/br.c	Sat Sep 21 11:02:25 1996
@@ -1137,7 +1137,6 @@
 						/* happen in net_bh() in dev.c) */
 			}
 			/* ok, forward this frame... */
-			skb_device_lock(skb);
 			return(br_forward(skb, port));
 		default:
 			printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
diff -u --recursive --new-file lx2.0/v2.0.21/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- lx2.0/v2.0.21/linux/net/ipv4/icmp.c	Sun Sep  8 19:50:22 1996
+++ linux/net/ipv4/icmp.c	Wed Sep 25 11:10:02 1996
@@ -36,6 +36,8 @@
  *	Willy Konynenberg	:	Transparent proxying support.
  *		Keith Owens	:	RFC1191 correction for 4.2BSD based 
  *					path MTU bug.
+ *		Thomas Quinot	:	ICMP Dest Unreach codes up to 15 are
+ *					valid (RFC 1812).
  *
  *
  * RFC1122 (Host Requirements -- Comm. Layer) Status:
@@ -732,7 +734,7 @@
 			default:
 				break;
 		}
-		if(icmph->code>12)	/* Invalid type */
+		if(icmph->code>15)	/* Invalid type */
 			return;
 	}
 	
diff -u --recursive --new-file lx2.0/v2.0.21/linux/net/socket.c linux/net/socket.c
--- lx2.0/v2.0.21/linux/net/socket.c	Mon Jul 15 11:31:51 1996
+++ linux/net/socket.c	Sat Sep 28 23:58:26 1996
@@ -80,12 +80,12 @@
 extern void export_net_symbols(void);
 #endif
 
-static int sock_lseek(struct inode *inode, struct file *file, off_t offset,
-		      int whence);
-static int sock_read(struct inode *inode, struct file *file, char *buf,
-		     int size);
-static int sock_write(struct inode *inode, struct file *file, const char *buf,
-		      int size);
+static long long sock_lseek(struct inode *inode, struct file *file,
+			    long long offset, int whence);
+static long sock_read(struct inode *inode, struct file *file,
+		      char *buf, unsigned long size);
+static long sock_write(struct inode *inode, struct file *file,
+		       const char *buf, unsigned long size);
 
 static void sock_close(struct inode *inode, struct file *file);
 static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
@@ -316,9 +316,10 @@
  *	Sockets are not seekable.
  */
 
-static int sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence)
+static long long sock_lseek(struct inode *inode, struct file *file,
+	long long offset, int whence)
 {
-	return(-ESPIPE);
+	return -ESPIPE;
 }
 
 /*
@@ -326,7 +327,8 @@
  *	area ubuf...ubuf+size-1 is writable before asking the protocol.
  */
 
-static int sock_read(struct inode *inode, struct file *file, char *ubuf, int size)
+static long sock_read(struct inode *inode, struct file *file,
+	char *ubuf, unsigned long size)
 {
 	struct socket *sock;
 	int err;
@@ -358,7 +360,8 @@
  *	readable by the user process.
  */
 
-static int sock_write(struct inode *inode, struct file *file, const char *ubuf, int size)
+static long sock_write(struct inode *inode, struct file *file,
+	const char *ubuf, unsigned long size)
 {
 	struct socket *sock;
 	int err;
diff -u --recursive --new-file lx2.0/v2.0.21/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- lx2.0/v2.0.21/linux/scripts/mkdep.c	Fri Sep 20 17:00:36 1996
+++ linux/scripts/mkdep.c	Sat Sep 21 10:46:07 1996
@@ -57,25 +57,29 @@
 #endif
 
 #ifdef LE_MACHINE
-#define first_byte(x) current = (unsigned char) x; x >>= 8;
+#define next_byte(x) (x >>= 8)
+#define current ((unsigned char) __buf)
 #else
-#define first_byte(x) current = x >> 8*(sizeof(unsigned long)-1); x <<= 8;
+#define next_byte(x) (x <<= 8)
+#define current (__buf >> 8*(sizeof(unsigned long)-1))
 #endif
 
 #define GETNEXT { \
-if (!__buf) { \
+next_byte(__buf); \
+if (!__nrbuf) { \
 	__buf = *(unsigned long *) next; \
+	__nrbuf = sizeof(unsigned long); \
 	if (!__buf) \
 		break; \
-} first_byte(__buf); next++; }
+} next++; __nrbuf--; }
 #define CASE(c,label) if (current == c) goto label
 #define NOTCASE(c,label) if (current != c) goto label
 
-static void state_machine(char *next)
+static void state_machine(register char *next)
 {
 	for(;;) {
-	unsigned long __buf = 0;
-	unsigned char current;
+	register unsigned long __buf = 0;
+	register unsigned long __nrbuf = 0;
 
 normal:
 	GETNEXT
@@ -181,19 +185,33 @@
 	if (needsconfig)
 		goto skippreproc;
 if_start:
-	if (!memcmp("CONFIG_", next, 7)) {
-		handle_config();
-		goto skippreproc;
-	}
 	GETNEXT
+	CASE('C', config);
 	CASE('\n', normal);
 	CASE('_', if_middle);
 	if (current >= 'a' && current <= 'z')
 		goto if_middle;
 	if (current < 'A' || current > 'Z')
 		goto if_start;
+config:
+	GETNEXT
+	NOTCASE('O', __if_middle);
+	GETNEXT
+	NOTCASE('N', __if_middle);
+	GETNEXT
+	NOTCASE('F', __if_middle);
+	GETNEXT
+	NOTCASE('I', __if_middle);
+	GETNEXT
+	NOTCASE('G', __if_middle);
+	GETNEXT
+	NOTCASE('_', __if_middle);
+	handle_config();
+	goto skippreproc;
+
 if_middle:
 	GETNEXT
+__if_middle:
 	CASE('\n', normal);
 	CASE('_', if_middle);
 	if (current >= 'a' && current <= 'z')
