]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.0 2.1.0
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:31 +0000 (15:12 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:31 +0000 (15:12 -0500)
271 files changed:
CREDITS
Documentation/CodingStyle
Documentation/IO-mapping.txt [new file with mode: 0644]
Documentation/cdrom/ide-cd
Documentation/ide.txt
Documentation/locks.txt
Documentation/mandatory.txt
MAINTAINERS
Makefile
README
arch/alpha/kernel/ptrace.c
arch/alpha/mm/init.c
arch/i386/Makefile
arch/i386/boot/Makefile
arch/i386/boot/compressed/Makefile
arch/i386/boot/compressed/misc.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/bios32.c
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/ksyms.c
arch/i386/kernel/ldt.c
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/traps.c
arch/i386/kernel/vm86.c
arch/i386/lib/checksum.c
arch/i386/math-emu/fpu_emu.h
arch/i386/mm/Makefile
arch/i386/mm/fault.c
arch/i386/mm/init.c
arch/i386/mm/ioremap.c [new file with mode: 0644]
arch/m68k/Makefile
arch/m68k/Makefile_elf [deleted file]
arch/m68k/amiga/Makefile
arch/m68k/amiga/amifb.c
arch/m68k/amiga/amiints.c
arch/m68k/amiga/amikeyb.c
arch/m68k/amiga/amisound.c
arch/m68k/amiga/chipram.c
arch/m68k/amiga/cia.c [new file with mode: 0644]
arch/m68k/amiga/config.c
arch/m68k/amiga/cyberfb.c
arch/m68k/amiga/ksyms.c
arch/m68k/amiga/zorro.c
arch/m68k/atari/Makefile
arch/m68k/atari/atafb.c
arch/m68k/atari/ataints.c
arch/m68k/atari/atakeyb.c
arch/m68k/atari/atari.mup [deleted file]
arch/m68k/atari/atasound.c
arch/m68k/atari/config.c
arch/m68k/atari/ksyms.c
arch/m68k/atari/stdma.c
arch/m68k/atari/stram.c
arch/m68k/boot/Makefile
arch/m68k/boot/amiga/bootstrap.c
arch/m68k/boot/amiga/bootstrap.h
arch/m68k/boot/amiga/linuxboot.c [new file with mode: 0644]
arch/m68k/boot/amiga/linuxboot.h [new file with mode: 0644]
arch/m68k/boot/atari/Makefile [deleted file]
arch/m68k/boot/atari/bootp.c [new file with mode: 0644]
arch/m68k/boot/atari/bootp.h [new file with mode: 0644]
arch/m68k/boot/atari/bootstrap.c
arch/m68k/boot/atari/ethlance.c [new file with mode: 0644]
arch/m68k/boot/atari/ethlance.h [new file with mode: 0644]
arch/m68k/config.in
arch/m68k/console/Makefile
arch/m68k/console/fbcon.c
arch/m68k/console/fonts.c
arch/m68k/defconfig
arch/m68k/fpsp040/skeleton.S
arch/m68k/ifpsp060/Makefile
arch/m68k/ifpsp060/fskeleton.S
arch/m68k/ifpsp060/iskeleton.S
arch/m68k/ifpsp060/os.S
arch/m68k/kernel/Makefile
arch/m68k/kernel/console.c
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/ints.c
arch/m68k/kernel/ksyms.c
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/setup.c
arch/m68k/kernel/signal.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/time.c
arch/m68k/kernel/traps.c
arch/m68k/lib/Makefile
arch/m68k/lib/memcpy.c
arch/m68k/lib/memset.c [new file with mode: 0644]
arch/m68k/lib/semaphore.S [new file with mode: 0644]
arch/m68k/mm/fault.c
arch/m68k/mm/init.c
arch/m68k/mm/memory.c
arch/m68k/tools/amiga/Makefile [new file with mode: 0644]
arch/m68k/tools/amiga/dmesg.c
drivers/block/floppy.c
drivers/block/ide-tape.c
drivers/block/ide-tape.h
drivers/block/ide.c
drivers/block/ide.h
drivers/block/triton.c
drivers/block/xd.c
drivers/block/xd.h [new file with mode: 0644]
drivers/cdrom/sbpcd.c
drivers/char/apm_bios.c
drivers/char/atixlmouse.c
drivers/char/busmouse.c
drivers/char/cyclades.c
drivers/char/ftape/kernel-interface.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/msbusmouse.c
drivers/char/psaux.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/selection.h
drivers/char/tpqic02.c
drivers/char/tty_io.c
drivers/char/vc_screen.c
drivers/net/bsd_comp.c
drivers/net/dgrs.c
drivers/net/dgrs_driver.c
drivers/net/eexpress.c
drivers/net/eexpress.h [new file with mode: 0644]
drivers/net/eql.c
drivers/net/eth82586.h [deleted file]
drivers/net/hp100.c
drivers/scsi/53c7,8xx.c
drivers/scsi/AM53C974.c
drivers/scsi/AM53C974.h
drivers/scsi/Makefile
drivers/scsi/README.in2000 [new file with mode: 0644]
drivers/scsi/advansys.c
drivers/scsi/advansys.h
drivers/scsi/aha152x.c
drivers/scsi/aha1542.c
drivers/scsi/in2000.c
drivers/scsi/in2000.h
drivers/scsi/in2000.readme [deleted file]
drivers/scsi/ncr53c8xx.c
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/sr.c
drivers/scsi/u14-34f.c
drivers/sound/configure.c
drivers/sound/dev_table.c
drivers/sound/os.h
drivers/sound/soundcard.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/block_dev.c
fs/buffer.c
fs/dquot.c
fs/exec.c
fs/ext/dir.c
fs/ext/file.c
fs/ext2/dir.c
fs/ext2/file.c
fs/fat/dir.c
fs/fat/file.c
fs/fat/misc.c
fs/hpfs/hpfs_fs.c
fs/locks.c
fs/minix/dir.c
fs/minix/file.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/file.c
fs/pipe.c
fs/proc/array.c
fs/proc/kmsg.c
fs/proc/mem.c
fs/proc/net.c
fs/proc/scsi.c
fs/read_write.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/proc.c
fs/sysv/dir.c
fs/sysv/file.c
fs/umsdos/dir.c
fs/umsdos/file.c
fs/umsdos/symlink.c
fs/xiafs/dir.c
fs/xiafs/file.c
include/asm-alpha/fcntl.h
include/asm-alpha/floppy.h
include/asm-alpha/io.h
include/asm-alpha/page.h
include/asm-alpha/pgtable.h
include/asm-alpha/segment.h
include/asm-i386/checksum.h
include/asm-i386/dma.h
include/asm-i386/fcntl.h
include/asm-i386/floppy.h
include/asm-i386/io.h
include/asm-i386/irq.h
include/asm-i386/ldt.h [new file with mode: 0644]
include/asm-i386/page.h
include/asm-i386/pgtable.h
include/asm-i386/processor.h
include/asm-i386/segment.h
include/asm-i386/system.h
include/asm-m68k/amigahw.h
include/asm-m68k/amigaints.h
include/asm-m68k/atari_acsi.h [new file with mode: 0644]
include/asm-m68k/atari_rootsec.h
include/asm-m68k/atari_stdma.h
include/asm-m68k/atarihw.h
include/asm-m68k/atariints.h
include/asm-m68k/bitops.h
include/asm-m68k/bootinfo.h [deleted file]
include/asm-m68k/byteorder.h
include/asm-m68k/delay.h
include/asm-m68k/errno.h
include/asm-m68k/fcntl.h
include/asm-m68k/ioctl.h
include/asm-m68k/irq.h
include/asm-m68k/machdep.h
include/asm-m68k/page.h
include/asm-m68k/pgtable.h
include/asm-m68k/posix_types.h
include/asm-m68k/processor.h
include/asm-m68k/resource.h
include/asm-m68k/segment.h
include/asm-m68k/semaphore.h [new file with mode: 0644]
include/asm-m68k/setup.h [new file with mode: 0644]
include/asm-m68k/string.h
include/asm-m68k/system.h
include/asm-m68k/unistd.h
include/asm-m68k/zorro.h
include/asm-mips/fcntl.h
include/asm-mips/floppy.h
include/asm-ppc/fcntl.h
include/asm-ppc/floppy.h
include/asm-sparc/fcntl.h
include/linux/fs.h
include/linux/ldt.h [deleted file]
include/linux/mm.h
include/linux/msdos_fs.h
include/linux/sysv_fs.h
include/linux/umsdos_fs.p
include/linux/vmalloc.h [new file with mode: 0644]
include/linux/xd.h [deleted file]
include/net/ipx.h
init/main.c
kernel/fork.c
kernel/ksyms.c
kernel/module.c
kernel/sysctl.c
mm/filemap.c
mm/kmalloc.c
mm/memory.c
mm/mlock.c
mm/mmap.c
mm/page_alloc.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
net/bridge/br.c
net/ipv4/icmp.c
net/socket.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index 7b7e338e7cf0e25e52f0a3aa62301db19d1e9114..f5c2532683e182d14a95bbd8c81aadf7c66e0433 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1320,7 +1320,7 @@ N: Linus Torvalds
 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
index 47ec533fecb382602562b6bf0d643180a5e7b816..7d72179f726059e8457e0a83f7a4504dcdb3f014 100644 (file)
@@ -183,14 +183,8 @@ values.  To do the latter, you can stick the following in your .emacs file:
   "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 --git a/Documentation/IO-mapping.txt b/Documentation/IO-mapping.txt
new file mode 100644 (file)
index 0000000..ceac953
--- /dev/null
@@ -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
+
index 0edbd21bda94e11b3f3e05c3e2c6dc8ad4a863cc..22842fbd0e94308ce9b400b719977089394c3d79 100644 (file)
@@ -352,6 +352,14 @@ e. Directory listings are unpredictably truncated, and `dmesg' shows
     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
 -----------
 
index 2af4dd7a1683ac4fb8aa64850ef249fc8132a558..277382b8c069c77e0be40b1cdddc02f75917cd7a 100644 (file)
@@ -255,6 +255,8 @@ Summary of ide driver parameters for kernel "command line":
                                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,
index a619015f30781831b192f62e2ce5939c944b8bd8..41d54cbccc14fc2fa2f0b75b74adf0d788d4be63 100644 (file)
@@ -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 @@ especially with respect to parent-child lock sharing, and can give bad
 results if, for example, sendmail attempts to use them.
 
 Fixed versions of the C libraries have been on public release for many
-months. The latest versions 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 @@ file with flock(). With pre 1.3.96 kernels this could result in deadlocks that,
 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 @@ Some programs may break (again, groan). In particular the aforementioned
 sendmail may have problems running in 'newaliases' mode. It will no longer
 deadlock though. Recompile sendmail to use flock() and your troubles will
 be over.
-
index f80c04920a07e0f4341c3f453b59aea38c9da81b..1ef2788d88587026947c71e1d8c6f70a6b2acd99 100644 (file)
@@ -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 @@ Note 2: POSIX.1 does not specify any scheme for mandatory locking, despite
 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 @@ modified to recognize the special case of a mandatory lock candidate and to
 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 @@ I'm afraid that this is such an esoteric area that the semantics described
 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 @@ Semantics
    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 @@ Note 3: I may have overlooked some system calls that need mandatory lock
 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
index a800ae93aabfb5d909791b923bc78b98f5ea7703..69ce1486114b32f36a3c66907326ad9f41c2bd9e 100644 (file)
@@ -159,6 +159,12 @@ M: mike@i-Connect.Net
 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
index 600f7c2001be30a749a2d6bcad917d0c8991d4d7..0ee2a386dd230952cdf69c686cfee673e9382b28 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
-PATCHLEVEL = 0
-SUBLEVEL = 21
+PATCHLEVEL = 1
+SUBLEVEL = 0
 
 ARCH = i386
 
@@ -26,7 +26,7 @@ TOPDIR        := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
 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 --git a/README b/README
index 1414fd7229ad17870f3b9e8661fcfd89ce399910..86d459c877998709f77ef31cf41013c2cfa66bfd 100644 (file)
--- a/README
+++ b/README
@@ -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 @@ ON WHAT HARDWARE DOES IT RUN?
 
 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 @@ INSTALLING the kernel:
  - 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 @@ INSTALLING the kernel:
    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 @@ INSTALLING the kernel:
                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 @@ INSTALLING the kernel:
 
 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 @@ CONFIGURING the kernel:
 
 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 @@ COMPILING the kernel:
 
    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 @@ COMPILING the kernel:
    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 @@ IF SOMETHING GOES WRONG:
    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 @@ IF SOMETHING GOES WRONG:
    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 @@ IF SOMETHING GOES WRONG:
    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").
index 1fd5942c9079db2aa66e25641d34b5ba542b89b2..e133d61e9d73bd4cb7602bd6c6c2a7829bbe27f8 100644 (file)
@@ -197,7 +197,7 @@ repeat:
        }
        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 @@ repeat:
                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 */
index 12676f1aa55febcf7442c78d7c220ef364499dee..362651117defebc9c7e76c6b794e888e645e83ad 100644 (file)
@@ -59,7 +59,7 @@ void show_mem(void)
        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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                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 @@ void si_meminfo(struct sysinfo *val)
 {
        int i;
 
-       i = MAP_NR(high_memory);
+       i = max_mapnr;
        val->totalram = 0;
        val->sharedram = 0;
        val->freeram = nr_free_pages << PAGE_SHIFT;
index e5bb0e11c17501f5c92fae6d3b14eb3e9608afbe..429b2b2b4d96308ac1d5b1f9ccb30cd72763e0f7 100644 (file)
 # 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,22 +41,10 @@ ENCAPS=$(CROSS_COMPILE)encaps
 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
 
 ifdef CONFIG_M386
index 9c5227c8b99c968dbc63cc932b55646f24a41bcb..3431a9f8c75f4fed3fa21f8482d993e8ed542df0 100644 (file)
@@ -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
index 42a986ea28e0d05db28a977768012a33e7ef2675..d7f093e3f14ee8a591ebdcc4e9339fc7f8d500ae 100644 (file)
@@ -15,11 +15,9 @@ ifdef SMP
 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 @@ head.o: head.S $(TOPDIR)/include/linux/tasks.h
 
 endif
 
-ifdef CONFIG_KERNEL_ELF
 
 # You cannot compress a file and have the kernel uncompress it, it must
 # be stdin
@@ -61,18 +58,6 @@ piggy.o:     $(SYSTEM)
          $(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
index a3c8183749d3365336b97f1ff2fb50c7433222ea..296517feea0c55c265f61d92bb3cd9a299b6c370 100644 (file)
@@ -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;
index 0e207fa9a10ee8a6d49175b3ed95637700a8adaa..2948ab6378394802e8300535181ea10bd091970f 100644 (file)
@@ -36,7 +36,6 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 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     \
index 46869a69298a4888a39f3497b1a6e352a87a1945..af2623a81c8983cba6479ccb28542b15a02016d3 100644 (file)
@@ -24,7 +24,6 @@ CONFIG_PCI=y
 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
index 159fb8f5d351443414e6950437734019c3f56e9f..a1b49a3aed092991a1ac09244485d8d538a31f33 100644 (file)
@@ -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 @@ extern unsigned long check_pcibios(unsigned long memory_start, unsigned long mem
        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 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
         *
         */
 
-       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 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
                        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;
                        }
                }
        }
index 61eb608f839a1b0f14b73283bd39b6d992fe3e71..020f29d0098a19a07733d0d3cf96bec577a21ad2 100644 (file)
@@ -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 @@ ENOSYS = 38
        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 @@ ENOSYS = 38
 
 
 #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 @@ ENOSYS = 38
        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 @@ ENTRY(lcall7)
        pushfl                  # We get a different stack layout with call gates,
        pushl %eax              # which has to be cleaned up later..
        SAVE_ALL
+       GET_CURRENT
 #ifdef __SMP__
        ENTER_KERNEL
 #endif
@@ -281,6 +277,7 @@ reschedule:
 ENTRY(system_call)
        pushl %eax                      # save orig_eax
        SAVE_ALL
+       GET_CURRENT
 #ifdef __SMP__
        ENTER_KERNEL
 #endif
@@ -290,33 +287,11 @@ ENTRY(system_call)
        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 @@ ret_from_sys_call:
        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 @@ signal_return:
        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 @@ error_code:
        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(coprocessor_error)
 ENTRY(device_not_available)
        pushl $-1               # mark this as an int
        SAVE_ALL
+       GET_CURRENT
 #ifdef __SMP__
        ENTER_KERNEL
 #endif
index ca5a1666586384ba5fd2c5a543eebb4c226e4eb7..fdf38c8182e73ee9c0450aa03b6c6b8f8783c3a4 100644 (file)
 #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 @@ is386:      pushl %ecx              # restore original EFLAGS
        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 @@ is386:     pushl %ecx              # restore original EFLAGS
        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
@@ -271,61 +281,160 @@ rp_sidt:
        ret
 
 
-/*
- * 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 @@ ignore_int:
 .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 @@ gdt_descr:
 #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 @@ gdt_descr:
 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 */
index ea39097f358cbe2208f84807b56a2cea00689782..a333ccf48d8da6d28b785d2156f5d9bcb1c4c924 100644 (file)
@@ -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 @@ static struct symbol_table arch_symbol_table = {
        /* platform dependent support */
        X(dump_thread),
        X(dump_fpu),
+       X(ioremap),
        XNOVERS(down_failed),
        XNOVERS(up_wakeup),
 #ifdef __SMP__
index c5b8e1a9af222cd70f76e70e3eb63429a7a71070..b9a0ad5c8faee2e661730ed2268347c7903c7a7f 100644 (file)
@@ -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)
 {
index 89fe7b19eacb412094e26104b54ec4ac7ccd54d4..bf0e6a2ef456ded93f76d2e9cf626326ec6bc579 100644 (file)
 #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 @@ int cpu_idle(void *unused)
  * 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 @@ void hard_reset_now(void)
        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 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
        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;
index cd9543561c95ff699c53e0d8581d712f794a9738..f6461105f0ed552bb383acde83c420e96fabcbf3 100644 (file)
@@ -119,7 +119,7 @@ repeat:
        }
        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 @@ repeat:
                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 */
index d1f6123ea175e40d8764cca0aa78a9aa102221fc..c177e0ee3ee1ffd487babb65adb54bc93a2497d9 100644 (file)
@@ -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 @@ void setup_arch(char **cmdline_p,
        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 @@ void setup_arch(char **cmdline_p,
        }
        *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",
index 2ecfaee05c9f889529bb87257cc523a4e65da8a2..2d957268077fe827f00d6e60a90b110e032db749 100644 (file)
@@ -197,7 +197,7 @@ static void setup_frame(struct sigaction * sa,
        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);
index 129dc928a79b2bfa1b56642b906657cb3556b2d4..05c80b7112436442cb08bef90cd08e779a2476c0 100644 (file)
@@ -67,7 +67,7 @@ int apic_version[NR_CPUS];                            /* APIC version number                                  */
 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 @@ void smp_boot_cpus(void)
         *      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");
index 9492dae65c3f45c0986cc37d8e11d853b2a94d77..858bb901f2112a5e10992fa2727546334d2134d0 100644 (file)
@@ -134,7 +134,8 @@ int kstack_depth_to_print = 24;
        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 @@ void trap_init(void)
                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);
index 7d8ec4b931f6bf174277d4882f46874eeeb98e79..ea86ad49feada906a9f1cf710de50064c553f5f2 100644 (file)
@@ -102,10 +102,11 @@ static void mark_screen_rdonly(struct task_struct * tsk)
 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 @@ asmlinkage int sys_vm86(struct vm86_struct * v86)
 
        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 @@ asmlinkage int sys_vm86(struct vm86_struct * v86)
  * 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 @@ static inline void return_to_32bit(struct vm86_regs * regs16, int retval)
        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)
index 55be5b60c7627ae3f22d731b94974b70522ae909..d2bf48b087bbac734c91ba0fae9358232ffd201b 100644 (file)
@@ -97,101 +97,6 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
 
 
 
-/*
- * 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
  */
index 68c51cd9e4604af0e56ba55adf6edd924521cb41..b8385db1fe5b66d9b116089b5f04d2ad4dbcc98e 100644 (file)
@@ -97,9 +97,9 @@ extern char emulating;
 
 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;
index c59918932fe2b1b23ceda9df7bcf2ea4d4aa669a..e10f814ececb2cbbca3ae2a2bbcc57efe844f0d8 100644 (file)
@@ -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
index feb16196ee02c52c6ddc5843fc95239d7e52d388..92d4f195d92f1100c9da053a2a859283ad668747 100644 (file)
@@ -123,14 +123,14 @@ bad_area:
  *
  * 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 @@ bad_area:
        __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);
index 9fbfd3c09d24fb5cba2598e388e7ccbb7dcef77f..a2c54d98ced79d17e10bd898d1cc9c1aff4ac2d0 100644 (file)
@@ -81,7 +81,7 @@ void show_mem(void)
        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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
                                : : :"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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
         * 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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
 #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 @@ void si_meminfo(struct sysinfo *val)
 {
        int i;
 
-       i = high_memory >> PAGE_SHIFT;
+       i = max_mapnr;
        val->totalram = 0;
        val->sharedram = 0;
        val->freeram = nr_free_pages << PAGE_SHIFT;
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
new file mode 100644 (file)
index 0000000..42b386c
--- /dev/null
@@ -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);
+}
index 0802851e11f43c23337b8c256917ebdcc4cb9a3b..296437c5ec407cd96616289fd7534463ceada607 100644 (file)
@@ -21,7 +21,7 @@ CC    := $(CC)
 # 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 @@ LINKFLAGS = -Ttext 0x1000
 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 @@ endif
 # 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 --git a/arch/m68k/Makefile_elf b/arch/m68k/Makefile_elf
deleted file mode 100644 (file)
index e7bff67..0000000
+++ /dev/null
@@ -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
index 66ed5da0b0253d89749321bfd3a87b545c962a4e..ca540b9d11cde08f6c5503293f13033362cf68c1 100644 (file)
@@ -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
index 744358b4583ca86b14888041b8e0939b55c8bead..bd5a79ea04ec379e58e84e86e2bf456ae697c22a 100644 (file)
@@ -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):
  *
  *
  * 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>
 #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
 
 /*******************************************************************************
 
    -------------------------------------------
 
    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.
         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
    --------------
    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.
 
 
    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
 
       - 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 --
 *******************************************************************************/
 
 
-   /*
-    *    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)
 
-   /*
-    *    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;
-};
+#define NTSC_DIWSTRT_H (360)   /* NTSC Window Limits */
+#define NTSC_DIWSTRT_V (40)
+#define NTSC_HTOTAL    (1816)
+#define NTSC_VTOTAL    (525)
 
 
-   /*
-    *    Long Frame/Short Frame Copper List
-    */
+       /*
+        * Monitor Specifications
+        *
+        * These are typical for a `generic' Amiga monitor (e.g. A1960)
+        */
 
-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)
 
-   /*
-    *    Hardware Cursor
-    */
+#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 CRSR_RATE       (20)     /* Number of frames/flash toggle */
+#define up8(v)         (((v)+7) & -8)
+#define down8(v)       ((v) & -8)
+#define div8(v)                ((v)>>3)
+#define mod8(v)                ((v) & 7)
 
-static u_long *lofsprite, *shfsprite, *dummysprite;
-static u_short cursormode = FB_CURSOR_FLASH;
+#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)
 
-   /*
-    *    Current Video Mode
-    */
+#define up64(v)                (((v)+63) & -64)
+#define down64(v)      ((v) & -64)
+#define div64(v)       ((v)>>6)
+#define mod64(v)       ((v) & 63)
 
-struct amiga_fb_par {
+#define upx(x,v)       (((v)+(x)-1) & -(x))
+#define downx(x,v)     ((v) & -(x))
+#define modx(x,v)      ((v) & ((x)-1))
 
-   /* General Values */
-
-   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) */
+/* 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;})
 
-#if defined(CONFIG_AMIFB_AGA)
-   /* Additional AGA Hardware Registers */
+#define min(a, b)      ((a) < (b) ? (a) : (b))
+#define max(a, b)      ((a) > (b) ? (a) : (b))
 
-   u_short fmode;                /* vmode */
-#endif /* defined(CONFIG_AMIFB_AGA) */
-};
+#define highw(x)       ((u_long)(x)>>16 & 0xffff)
+#define loww(x)                ((u_long)(x) & 0xffff)
 
-static struct amiga_fb_par current_par;
+#define arraysize(x)   (sizeof(x)/sizeof(*(x)))
 
-static int current_par_valid = 0;
-static int currcon = 0;
+#define VBlankOn()     custom.intena = IF_SETCLR|IF_COPER
+#define VBlankOff()    custom.intena = IF_COPER
 
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
 
-static int node;        /* node of the /dev/fb?current file */
+       /*
+        * Chip RAM we reserve for the Frame Buffer
+        *
+        * This defines the Maximum Virtual Screen Size
+        * (Setable per kernel options?)
+        */
 
+#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 */
 
-   /*
-    *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-    *    (Imported from arch/m68k/amiga/amisound.c)
-    */
+#define SPRITEMEMSIZE          (64*64/4) /* max 64*64*4 */
+#define DUMMYSPRITEMEMSIZE     (8)
 
-extern volatile u_short amiga_audio_min_period;
+static u_long videomemory, spritememory;
+static u_long videomemorysize;
 
+       /*
+        * 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
+        */
 
-   /*
-    *    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.
-    */
+static u_long min_fstrt = 192;
 
-#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 */
+#define assignchunk(name, type, ptr, size) \
+{ \
+       (name) = (type)(ptr); \
+       ptr += size; \
+}
 
 
-   /*
-    *    Latches and Flags for display changes during VBlank
-    */
+       /*
+        * Copper Instructions
+        */
 
-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 */
+#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)
 
 
-   /*
-    *    Switch for Chipset Independency
-    */
+typedef union {
+       u_long l;
+       u_short w[2];
+} copins;
 
-static struct fb_hwswitch {
+struct copdisplay {
+       copins *init;
+       copins *wait;
+       copins *list[2][2];
+       copins *rebuild[2];
+} copdisplay;
 
-   /* Initialization */
-   int (*init)(void);
+static u_short currentcop = 0;
 
-   /* 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);
+       /*
+        * Hardware Cursor
+        */
 
-   /* 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;
+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;
 
-   /*
-    *    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 */
+
+       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 */
+
+       /* Additional AGA Hardware Registers */
+
+       u_short fmode;          /* vmode */
+} currentpar;
 
-   /*
-    *    Predefined Video Mode Names
-    *
-    *    The a2024-?? modes don't work yet because there's no A2024 driver.
-    */
+static int currcon = 0;
 
-static char *amiga_fb_modenames[] = {
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
 
-   /*
-    *    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
-    */
-
-   "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
+static int node;               /* node of the /dev/fb?current file */
 
+       /*
+        * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+        * (Imported from arch/m68k/amiga/amisound.c)
+        */
 
-   /*
-    *    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
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
+extern volatile u_short amiga_audio_min_period;
 
+       /*
+        * 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.
+        */
 
-#define NUM_USER_MODES     (8)
-#define NUM_TOTAL_MODES    arraysize(amiga_fb_predefined)
-#define NUM_PREDEF_MODES   (NUM_TOTAL_MODES-NUM_USER_MODES)
+#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
 
+#if defined(CONFIG_AMIFB_ECS)
+static u_short ecs_palette[32];
+#endif
 
-static int amifb_ilbm = 0;       /* interleaved or normal bitplanes */
+       /*
+        * Latches for Display Changes during VBlank
+        */
 
-static int amifb_inverse = 0;
-static int amifb_mode = 0;
+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
-    */
+       /*
+        * Various Flags
+        */
 
-#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);
+static u_short is_blanked = 0;         /* Screen is Blanked */
+static u_short is_lace = 0;            /* Screen is laced */
 
-static int amifb_Cyber = 0;
-#endif /* CONFIG_FB_CYBER */
+       /*
+        * Frame Buffer Name
+        *
+        * The rest of the name is filled in during initialization
+        */
 
+static char amiga_fb_name[16] = "Amiga ";
 
-   /*
-    *    Some default modes
-    */
+       /*
+        * Predefined Video Mode Names
+        *
+        * The a2024-?? modes don't work yet because there's no A2024 driver.
+        */
 
-#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_modenames[] = {
 
+       /*
+        * Autodetect (Default) Video Mode
+        */
 
-   /*
-    *    Interface used by the world
-    */
+       "default",
 
-void amiga_video_setup(char *options, int *ints);
+       /*
+        * AmigaOS Video Modes
+        */
 
-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);
+       "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 */
 
-static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                          u_long arg, int con);
+       /*
+        * VGA 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);
+       "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
+        */
 
-   /*
-    *    Interface to the low level console driver
-    */
+       "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
+};
 
-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);
+struct fb_var_screeninfo amiga_fb_predefined[] = {
 
+       /*
+        * Autodetect (Default) Video Mode
+        */
 
-   /*
-    *    Support for OCS
-    */
+       { 0, },
 
-#ifdef CONFIG_AMIFB_OCS
-#error "OCS support: not yet implemented"
-#endif /* CONFIG_AMIFB_OCS */
+       /*
+        * 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, 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
 
-   /*
-    *    Support for ECS
-    */
+       }, {
+               /* 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
+       },
 
-#ifdef CONFIG_AMIFB_ECS
-#error "ECS support: not yet implemented"
-#endif /* CONFIG_AMIFB_ECS */
+       /*
+        * 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 | 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
+       },
 
-   /*
-    *    Support for AGA
-    */
+       /*
+        * User Defined 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 */
+       { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
+};
 
+#define NUM_USER_MODES   (8)
+#define NUM_TOTAL_MODES  arraysize(amiga_fb_predefined)
+#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES)
 
-   /*
-    *    Internal routines
-    */
+static int amifb_ilbm = 0;     /* interleaved or normal bitplanes */
 
-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);
+static int amifb_inverse = 0;
+static int amifb_usermode = 0;
 
+       /*
+        * Some default modes
+        */
 
-#ifdef USE_MONO_AMIFB_IF_NON_AGA
+#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 */
 
-/******************************************************************************
-*
-* 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.
-*
-******************************************************************************/
+       /*
+        * 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
+        */
 
-/*
- * 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.
- */
+/* bplcon1 (smooth scrolling) */
 
-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 hscroll2hw(hscroll) \
+       (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
+        ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
 
+/* diwstrt/diwstop/diwhigh (visible display window) */
 
-/*
- *  Color definitions
- */
+#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))
 
-#define FG_COLOR               (0x000000)      /* black */
-#define BG_COLOR               (0xaaaaaa)      /* lt. grey */
-#define CRSR_COLOR             (0xff0000)      /* bright red */
+/* ddfstrt/ddfstop (display DMA) */
 
-#define FG_COLOR_INV           BG_COLOR
-#define BG_COLOR_INV           FG_COLOR
-#define CRSR_COLOR_INV         (0x6677aa)      /* a blue-ish color */
+#define ddfstrt2hw(ddfstrt)    div8(ddfstrt)
+#define ddfstop2hw(ddfstop)    div8(ddfstop)
 
-/*
- *  Split 24-bit RGB colors in 12-bit MSB (for OCS/ECS/AGA) and LSB (for AGA)
- */
+/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
 
-#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 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))
 
-/* Cursor definitions */
+/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
 
-#define CRSR_FLASH             1       /* Cursor flashing on(1)/off(0) */
-#define CRSR_BLOCK             1       /* Block(1) or line(0) cursor */
+#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 */
 
-/* controlling screen blanking (read in VBL handler) */
-static int mono_do_blank;
-static int mono_do_unblank;
-static unsigned short mono_save_bplcon3;
+#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))
 
-/*
- * 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)
- */
+/* sprpos/sprctl (sprite positioning) */
 
-static ushort mono_ecs_color_zero;
+#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 struct {
-       int right_count;
-       int done;
-} mono_vblank;
+/* get current vertical position of beam */
+#define get_vbpos()    ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
 
+       /*
+        * Copper Initialisation List
+        */
 
-static __inline__ void mono_init_vblank(void)
-{
-       mono_vblank.right_count = 0;
-       mono_vblank.done = 0;
-}
+#define COPINITSIZE (sizeof(copins)*40)
 
-/* 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 */
+enum {
+       cip_bplcon0
 };
 
-#define MAX_COP_LIST_ENTS 64
-#define COP_MEM_REQ       (MAX_COP_LIST_ENTS*4*2)
-#define SPR_MEM_REQ       (24)
+       /*
+        * Long Frame/Short Frame Copper List
+        * Don't change the order, build_copper()/rebuild_copper() rely on this
+        */
 
+#define COPLISTSIZE (sizeof(copins)*64)
 
-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.
-        */
-       {
-               "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 */
+enum {
+       cop_wait, cop_bplcon0,
+       cop_spr0ptrh, cop_spr0ptrl,
+       cop_diwstrt, cop_diwstop,
+       cop_diwhigh,
+};
 
-       },
-       /* 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
+        * Pixel modes for Bitplanes and Sprites
         */
-       {
-               /*
-                * 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))
-
-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 }
+static u_short bplpixmode[3] = {
+       BPC0_SHRES,                     /*  35 ns */
+       BPC0_HIRES,                     /*  70 ns */
+       0                               /* 140 ns */
 };
 
-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;
-
-                       /*
-                        * Under ECS we have to keep color[0], as it is part of a special color-table.
-                        */
+static u_short sprpixmode[3] = {
+       BPC3_SPRES1 | BPC3_SPRES0,      /*  35 ns */
+       BPC3_SPRES1,                    /*  70 ns */
+       BPC3_SPRES0                     /* 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;
+       /*
+        * Fetch modes for Bitplanes and Sprites
+        */
 
-       return(cop);
-}
+static u_short bplfetchmode[3] = {
+       0,                              /* 1x */
+       FMODE_BPL32,                    /* 2x */
+       FMODE_BPAGEM | FMODE_BPL32      /* 4x */
+};
 
+static u_short sprfetchmode[3] = {
+       0,                              /* 1x */
+       FMODE_SPR32,                    /* 2x */
+       FMODE_SPAGEM | FMODE_SPR32      /* 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;
+       /*
+        * Default Colormaps
+        */
 
-       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;
-       }
+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)
-               /*
-                * 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;
-
-       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;
-
-        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 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 };
 
-}
+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 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;
-       }
+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 };
 
-       /* 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];
-               }
-       }
+       mcap_spec[0] = '\0';
+       fb_info.fontname[0] = '\0';
 
-       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
-                */
+       if (!options || !*options)
+               return;
 
-               /* We could load 8-bit colors here, if we wanted */
+       for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
+               char *p;
 
-               /*
-                *    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;
+               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;
 
-       /* Build initial copper lists. sprites must be set up, and mono_current_par.diwstrt. */
+       if (*mcap_spec) {
+               char *p;
+               int vmin, vmax, hmin, hmax;
 
-       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);
+       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+        * <V*> vertical freq. in Hz
+        * <H*> horizontal freq. in kHz
+        */
 
-               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);
+               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:
+               ;
        }
+}
 
+       /*
+        * Get the Fixed Part of the Display
+        */
 
-       /* 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 */
-
-               /* wait for LOF frame bit to go low */
-               while (custom.vposr & 0x8000)
-                       ;
+static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+{
+       struct amiga_fb_par par;
 
-               /* wait for LOF frame bit to go high */
-               while (!(custom.vposr & 0x8000))
-                       ;
+       if (con == -1)
+               ami_get_par(&par);
+       else {
+               int err;
 
-               /* start again at the beginning of copper list 1 */
-               custom.cop1lc = mono_current_par.coplist1hdr;
-               custom.copjmp1 = 0;
+               if ((err = ami_decode_var(&disp[con].var, &par)))
+                       return err;
        }
+       return ami_encode_fix(fix, &par);
 }
 
+       /*
+        * Get the User Defined Part of the Display
+        */
 
-static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data)
+static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
 {
-       register struct display *p = disp;
+       int err = 0;
 
-       static ushort cursorcount = 0;
-       static ushort cursorstate = 0;
+       if (con == -1) {
+               struct amiga_fb_par par;
 
-       /* 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
+               ami_get_par(&par);
+               err = ami_encode_var(var, &par);
+       } else
+               *var = disp[con].var;
+       return err;
+}
+
+       /*
+        * Set the User Defined Part of the Display
         */
 
-       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);
+static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
+{
+       int err, activate = var->activate;
+       int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+       struct amiga_fb_par par;
 
-               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;
+       /*
+        * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+        * as FB_VMODE_SMOOTH_XPAN is only used internally
+        */
 
-       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 (var->vmode & FB_VMODE_CONUPDATE) {
+               var->vmode |= FB_VMODE_YWRAP;
+               var->xoffset = disp[con].var.xoffset;
+               var->yoffset = disp[con].var.yoffset;
        }
-
-       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;
+       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);
                }
-               /* 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;
+               if (oldbpp != var->bits_per_pixel) {
+                       if ((err = alloc_cmap(&disp[con].cmap, 0, 0)))
+                               return err;
+                       do_install_cmap(con);
                }
-               mono_do_unblank = 0;
+               if (con == currcon)
+                       ami_set_var(&disp[con].var);
        }
-
-       mono_vblank.done = 1;
+       return 0;
 }
 
-
-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
+        * Pan or Wrap the Display
+        *
+        * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
         */
 
-       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_pan_display(struct fb_var_screeninfo *var, 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;
-
-       var->bits_per_pixel = mono_current_par.geometry->scr_depth;
-       var->grayscale = 0;
-
-       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;
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->yoffset<0 || var->yoffset >= disp[con].var.yres_virtual || var->xoffset)
+                       return -EINVAL;
        } else {
-               var->red.offset = 0;
-               var->red.length = 4;
-               var->red.msb_right = 0;
-               var->green = var->red;
-               var->blue = var->red;
+               /*
+                * 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;
        }
-
-       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;
+       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
-               var->vmode = FB_VMODE_NONINTERLACED;
-
-       for (i = 0; i < arraysize(var->reserved); i++)
-               var->reserved[i] = 0;
-
-       return(0);
+               disp[con].var.vmode &= ~FB_VMODE_YWRAP;
+       return 0;
 }
 
+       /*
+        * Get the Colormap
+        */
 
-static void mono_amiga_fb_set_disp(int con)
+static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
 {
-       struct fb_fix_screeninfo fix;
-
-       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 == 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;
 }
 
-
-static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
        /*
-        *              Not yet implemented
+        * Set the Colormap
         */
-       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_cmap(struct fb_cmap *cmap, int kspc, int con)
 {
-       int i, start;
-       unsigned short *red, *green, *blue, *transp;
-       unsigned int hred, hgreen, hblue, htransp;
-       struct fb_cmap *def_cmap;
-
-       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;
+       int err;
 
-       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);
-               }
-               red++;
-               green++;
-               blue++;
-               if (transp)
-                       transp++;
+       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;
        }
-       return(0);
+       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;
 }
 
-
-static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
        /*
-        *              Not yet implemented
+        * Amiga Frame Buffer Specific ioctls
         */
-       return(-EINVAL);
-}
-
 
-static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
+static int amiga_fb_ioctl(struct inode *inode, struct file *file,
+                          u_int cmd, u_long arg, int con)
 {
-       /*
-        *              Not yet implemented
-        */
-       return(-EINVAL);
-}
-
+       int i;
 
-static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                                                                 unsigned long arg, int con)
-{
-       return(-EINVAL);
-}
+       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;
 
-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  
-};
+                       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;
 
+                       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;
 
-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);
+                       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;
 }
 
+       /*
+        * Hardware Cursor
+        */
 
-static int mono_amifb_updatevar(int con)
+static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, 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);
+       return ami_get_fix_cursorinfo(fix, con);
 }
 
-
-static void mono_amifb_blank(int blank)
+static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
 {
-       if (blank)
-               mono_do_blank = 1;
-       else
-               mono_do_unblank = 1;
+       return ami_get_var_cursorinfo(var, data, con);
 }
 
-
-static struct fb_info *mono_amiga_fb_init(long *mem_start)
+static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, 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;
-       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);
+       return ami_set_var_cursorinfo(var, data, con);
 }
-#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.
-    */
-
-static int ocs_init(void)
+static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, 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;
-
-
-   ...
-   ...
-   ...
-
-
-   /*
-    *    Enable Display DMA
-    */
-
-   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                   DMAF_SPRITE;
-
-   return(0);
+       return ami_get_cursorstate(state, con);
 }
-#endif /* CONFIG_AMIFB_OCS */
-
-
-/* -------------------- 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_set_cursorstate(struct fb_cursorstate *state, 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);
+       return ami_set_cursorstate(state, con);
 }
-#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))
+       /*
+        * Initialisation
+        */
 
-#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))
+struct fb_info *amiga_fb_init(long *mem_start)
+{
+       int err, tag, i;
+       u_long chipptr;
 
-/* sprpos/sprctl (sprite positioning) */
+       /*
+        * Check for a Graphics Board
+        */
 
-#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;
-};
+#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
 
-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];
-};
+       /*
+        * Use the Builtin Chipset
+        */
 
+       if (!AMIGAHW_PRESENT(AMI_VIDEO))
+               return NULL;
 
-   /*
-    *    Pixel modes for Bitplanes and Sprites
-    */
+       custom.dmacon = DMAF_ALL | DMAF_MASTER;
 
-static u_short bplpixmode[3] = {
-   BPC0_SHRES,                   /*  35 ns / 28 MHz */
-   BPC0_HIRES,                   /*  70 ns / 14 MHz */
-   0                             /* 140 ns /  7 MHz */
-};
+       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 */
 
-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 */
-};
+#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 */
 
+#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 */
 
-   /*
-    *    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.
-    */
+               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 int aga_init(void)
-{
-   u_long p;
+       /*
+        * Calculate the Pixel Clock Values for this Machine
+        */
 
-   /*
-    *    Disable Display DMA
-    */
+       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 */
 
-   custom.dmacon = DMAF_ALL | DMAF_MASTER;
+       /*
+        * Replace the Tag Values with the Real Pixel Clock Values
+        */
 
-   /*
-    *    Set the Default Video Mode
-    */
+       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];
+               }
+       }
 
-   if (!amifb_mode)
-      amifb_mode = get_video_mode(DEFMODE_AGA);
+       err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
+                                  NUM_TOTAL_MODES, amiga_fb_predefined);
+       if (err < 0)
+               panic("Cannot register frame buffer");
 
-   /*
-    *    Allocate Chip RAM Structures
-    */
+       chipptr = chipalloc(videomemorysize+
+                           SPRITEMEMSIZE+
+                           DUMMYSPRITEMEMSIZE+
+                           COPINITSIZE+
+                           4*COPLISTSIZE);
 
-   if (boot_info.bi_amiga.chip_size > 1048576)
-      videomemorysize = VIDEOMEMSIZE_AGA_2M;
-   else
-      videomemorysize = VIDEOMEMSIZE_AGA_1M;
+       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);
 
-   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));
+       memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
 
-   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));
+       /*
+        * Enable Display DMA
+        */
 
-   /*
-    *    Make sure the Copper has something to do
-    */
+       custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+                       DMAF_BLITTER | DMAF_SPRITE;
 
-   aga_build_clist_hdr(clist_hdr);
+       /*
+        * Make sure the Copper has something to do
+        */
 
-   custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr);
-   custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever);
-   custom.copjmp1 = 0;
+       ami_init_copper();
 
-   /*
-    *    Enable Display DMA
-    */
+       check_default_mode();
 
-   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                   DMAF_SPRITE;
+       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;
 
-   /*
-    *    These hardware register values will never be changed later
-    */
+       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;
 
-   custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2;
-   custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+       amiga_fb_set_var(&amiga_fb_predefined[0], 0);
 
-   return(0);
+       return &fb_info;
 }
 
+static int amifbcon_switch(int con)
+{
+       /* Do we have to save the colormap? */
+       if (disp[currcon].cmap.len)
+               do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
 
-   /*
-    *    This function should fill in the `fix' structure based on the
-    *    values in the `par' structure.
-    */
+       currcon = con;
+       ami_set_var(&disp[con].var);
+       /* Install new colormap */
+       do_install_cmap(con);
+       return 0;
+}
 
-static int aga_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amiga_fb_par *par)
+       /*
+        * Update the `var' structure (called by amicon.c)
+        */
+
+static int amifbcon_updatevar(int con)
 {
-   int i;
-
-   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);
+       ami_pan_var(&disp[con].var);
+       return 0;
 }
 
+       /*
+        * Blank the display.
+        */
 
-   /*
-    *    Get the video params out of `var'. If a value doesn't fit, round
-    *    it up, if it's too big, return -EINVAL.
-    */
-
-static int aga_decode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
+static void amifbcon_blank(int blank)
 {
-   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);
+       do_blank = blank ? blank : -1;
 }
 
+/* ---------------------------- Generic routines ---------------------------- */
 
-   /*
-    *    Fill the `var' structure based on the values in `par' and maybe
-    *    other values read out of the hardware.
-    */
-
-static int aga_encode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
+static struct fb_cmap *get_default_colormap(int bpp)
 {
-   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);
+       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))
 
-   /*
-    *    Read a single color register and split it into
-    *    colors/transparent. Return != 0 for invalid regno.
-    */
-
-static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp)
+static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
+                          int kspc)
 {
-   if (regno > 255)
-      return(1);
+       int i, start;
+       u_short *red, *green, *blue, *transp;
+       u_int hred, hgreen, hblue, htransp;
 
-   *red = palette[regno].red;
-   *green = palette[regno].green;
-   *blue = palette[regno].blue;
-   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 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;
 
-   /*
-    *    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.
-    */
+       red = cmap->red;
+       green = cmap->green;
+       blue = cmap->blue;
+       transp = cmap->transp;
+       start = cmap->start;
 
-static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp)
-{
-   u_short bplcon3 = current_par.bplcon3;
-
-   if (regno > 255)
-      return(1);
-
-   /*
-    *    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);
+       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 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);
+}
 
-   /*
-    *    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)
+static void memcpy_fs(int fsfromto, void *to, void *from, int len)
 {
-   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);
+       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;
+       }
 }
 
+static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+{
+       int size;
+       int tooff = 0, fromoff = 0;
 
-   /*
-    *    Change the video mode (called by VBlank interrupt)
-    */
+       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);
+}
 
-void aga_do_vmode(void)
+static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
 {
-   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);
+       int size = len*sizeof(u_short);
+
+       if (cmap->len != len) {
+               if (cmap->red)
+                       kfree(cmap->red);
+               if (cmap->green)
+                       kfree(cmap->green);
+               if (cmap->blue)
+                       kfree(cmap->blue);
+               if (cmap->transp)
+                       kfree(cmap->transp);
+               cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
+               cmap->len = 0;
+               if (!len)
+                       return 0;
+               if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
+                       return -1;
+               if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
+                       return -1;
+               if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
+                       return -1;
+               if (transp) {
+                       if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
+                               return -1;
+               } else
+                       cmap->transp = NULL;
+       }
+       cmap->start = 0;
+       cmap->len = len;
+       copy_cmap(get_default_colormap(len), cmap, 0);
+       return 0;
 }
 
+static int flash_cursor(void)
+{
+       static int cursorcount = 1;
+
+       if (cursormode == FB_CURSOR_FLASH) {
+               if (!--cursorcount) {
+                       cursorstate = -cursorstate;
+                       cursorcount = cursorrate;
+                       if (!is_blanked)
+                               return 1;
+               }
+       }
+       return 0;
+}
 
-   /*
-    *    (Un)Blank the screen (called by VBlank interrupt)
-    */
+       /*
+        * VBlank Display Interrupt
+        */
 
-void aga_do_blank(int blank)
+static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
 {
-   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;
-}
+       u_short ints = custom.intreqr & custom.intenar;
+       static struct irq_server server = {0, 0};
 
+       if (ints & IF_BLIT) {
+               custom.intreq = IF_BLIT;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp);
+       }
 
-   /*
-    *    Move the cursor (called by VBlank interrupt)
-    */
+       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();
+               }
 
-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?
-    */
-}
+               if (get_vbpos() < down2(currentpar.diwstrt_v - 4))
+                       custom.copjmp2 = 0;
 
+               if (do_blank) {
+                       ami_do_blank();
+                       do_blank = 0;
+               }
 
-   /*
-    *    Flash the cursor (called by VBlank interrupt)
-    */
+               if (do_vmode_full) {
+                       ami_reinit_copper();
+                       do_vmode_full = 0;
+               }
+               amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server);
+       }
 
-void aga_do_flashcursor(void)
-{
-#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
+       if (ints & IF_VERTB) {
+               printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
+               custom.intena = IF_VERTB;
+       }
 }
 
+       /*
+        * Get a Video Modes
+        */
 
-#if 1
-static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static void get_video_mode(const char *name)
 {
-#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);
+       int i;
+
+       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
+        */
 
-static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static void check_default_mode(void)
 {
-   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+       struct amiga_fb_par par;
+       int mode;
 
-   /* TODO: interlaced sprites */
-   memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data));
-   return(0);
+       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 int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static u_long chipalloc(u_long size)
 {
-   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+       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);
 
-   /* TODO: interlaced sprites */
-   memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data));
-   return(0);
+       return ptr;
 }
 
+       /*
+        * A strtok which returns empty strings, too
+        */
 
-static int aga_get_cursorstate(struct fb_cursorstate *state, int con)
+static char *strtoke(char *s,const char *ct)
 {
-   state->xoffset = current_par.crsr_x;
-   state->yoffset = current_par.crsr_y;
-   state->mode = cursormode;
-   return(0);
+       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;
 }
 
+/* --------------------------- Hardware routines --------------------------- */
+
+       /*
+        * This function should fill in the `fix' structure based on the
+        * values in the `par' structure.
+        */
 
-static int aga_set_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_encode_fix(struct fb_fix_screeninfo *fix,
+                          struct amiga_fb_par *par)
 {
-   current_par.crsr_x = state->xoffset;
-   current_par.crsr_y = state->yoffset;
-   cursormode = state->mode;
-   do_movecursor = 1;
-   return(0);
-}
-#endif
+       int i;
 
+       strcpy(fix->id, amiga_fb_name);
+       fix->smem_start = videomemory;
+       fix->smem_len = videomemorysize;
 
-   /*
-    *    Build the Frame Header Copper List
-    */
+       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 __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;
-}
+       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;
 
+       return 0;
+}
 
-   /*
-    *    Update the Frame Header Copper List
-    */
+       /*
+        * Get the video params out of `var'. If a value doesn't fit, round
+        * it up, if it's too big, return -EINVAL.
+        */
 
-static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
-                                            struct amiga_fb_par *par)
+static int ami_decode_var(struct fb_var_screeninfo *var,
+                          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);
-}
+       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
+        */
 
-   /*
-    *    Build the Long Frame/Short Frame Copper List
-    */
+       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 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);
-   }
-
-   /* End of Copper list */
-   cop->rest[j++].l = CEND;
-
-   if (j > arraysize(cop->rest))
-      printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j);
-}
-#endif /* CONFIG_AMIFB_AGA */
+       /*
+        * 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;
 
-/* -------------------- Interfaces to hardware functions -------------------- */
+       /*
+        * 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;
 
-#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 */
+       /*
+        * Vertical and Horizontal Timings
+        */
 
-#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 */
+       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);
 
-#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 (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;
 
+       /*
+        * Checking the DMA timing
+        */
 
-/* -------------------- Generic routines ------------------------------------ */
+       fconst = 16<<maxfmode<<clk_shift;
 
+       /*
+        * smallest window start value without turn off other dma cycles
+        * than sprite1-7, unless you change min_fstrt
+        */
 
-   /*
-    *    Allocate, Clear and Align a Block of Chip Memory
-    */
 
-static u_long chipalloc(u_long size)
-{
-   u_long ptr;
+       fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
+       fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
+       if (fstrt < min_fstrt)
+               return -EINVAL;
 
-   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);
+       /*
+        * smallest window start value where smooth scrolling is possible
+        */
 
-   return(ptr);
-}
+       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);
 
-   /*
-    *    Fill the hardware's `par' structure.
-    */
+       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;
 
-static void amiga_fb_get_par(struct amiga_fb_par *par)
-{
-   if (current_par_valid)
-      *par = current_par;
-   else
-      fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par);
-}
+       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;
 
-static void amiga_fb_set_par(struct amiga_fb_par *par)
-{
-   do_vmode = 0;
-   current_par = *par;
-   full_vmode_change = 1;
-   do_vmode = 1;
-   current_par_valid = 1;
-}
+               fsize = up64(xres_n);
+               if (min_fstrt + fsize - 64 > maxfetchstop)
+                       return -EINVAL;
 
+               fsize -= 64;
+       } else
+               fsize -= fconst;
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-   int err, activate;
-   struct amiga_fb_par par;
-
-   if ((err = fbhw->decode_var(var, &par)))
-      return(err);
-   activate = var->activate;
-   if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-      amiga_fb_set_par(&par);
-   fbhw->encode_var(var, &par);
-   var->activate = activate;
-   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;
 
-   /*
-    *    Default Colormaps
-    */
+       /*
+        * Bitplane calculations and check the Memory Requirements
+        */
 
-static u_short red2[] =
-   { 0x0000, 0xc000 };
-static u_short green2[] =
-   { 0x0000, 0xc000 };
-static u_short blue2[] =
-   { 0x0000, 0xc000 };
+       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;
+       }
 
-static u_short red4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short green4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short blue4[] =
-   { 0x0000, 0xc000, 0x8000, 0xffff };
+       /*
+        * Hardware Register Values
+        */
 
-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 };
+       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;
+       }
 
-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 ^ 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;
+
+       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;
+
+       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.
+        */
 
+static int ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par)
+{
+       u_short clk_shift, line_shift;
+       int i;
 
-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 };
+       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;
 
-static struct fb_cmap *get_default_colormap(int bpp)
-{
-   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;
-   }
-}
+       var->bits_per_pixel = par->bpp;
+       var->grayscale = 0;
 
+       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;
 
-#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
-                                              ((1<<(width))-1)) : 0))
+       if (par->bplcon0 & BPC0_HAM)
+               var->nonstd = FB_NONSTD_HAM;
+       else
+               var->nonstd = 0;
+       var->activate = 0;
 
-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);
-}
+       var->height = -1;
+       var->width = -1;
+       var->accel = 0;
 
+       var->pixclock = pixclock[clk_shift];
 
-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);
-}
+       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;
+       }
 
-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);
-}
+       if (par->bplcon0 & BPC0_ERSY)
+               var->sync |= FB_SYNC_EXT;
+       if (par->vmode & FB_VMODE_YWRAP)
+               var->vmode |= FB_VMODE_YWRAP;
 
+       for (i = 0; i < arraysize(var->reserved); i++)
+               var->reserved[i] = 0;
 
-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;
-   }
+       return 0;
 }
 
+       /*
+        * Get current hardware setting
+        */
 
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+static void ami_get_par(struct amiga_fb_par *par)
 {
-   int size;
-   int tooff = 0, fromoff = 0;
-
-   if (to->start > from->start)
-      fromoff = to->start-from->start;
-   else
-      tooff = from->start-to->start;
-   size = to->len-tooff;
-   if (size > from->len-fromoff)
-      size = from->len-fromoff;
-   if (size < 0)
-      return;
-   size *= sizeof(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);
+       *par = currentpar;
 }
 
+       /*
+        * Set new videomode
+        */
 
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+static void ami_set_var(struct fb_var_screeninfo *var)
 {
-   int size = len*sizeof(u_short);
-
-   if (cmap->len != len) {
-      if (cmap->red)
-         kfree(cmap->red);
-      if (cmap->green)
-         kfree(cmap->green);
-      if (cmap->blue)
-         kfree(cmap->blue);
-      if (cmap->transp)
-         kfree(cmap->transp);
-      cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-      cmap->len = 0;
-      if (!len)
-         return(0);
-      if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (transp) {
-         if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
-            return(-1);
-      } else
-         cmap->transp = NULL;
-   }
-   cmap->start = 0;
-   cmap->len = len;
-   copy_cmap(get_default_colormap(len), cmap, 0);
-   return(0);
+       do_vmode_pan = 0;
+       do_vmode_full = 0;
+       ami_decode_var(var, &currentpar);
+       ami_build_copper();
+       do_vmode_full = 1;
 }
 
-
-   /*
-    *    Get the Fixed Part of the Display
-    */
-
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+#ifdef DEBUG
+static void ami_set_par(struct amiga_fb_par *par)
 {
-   struct amiga_fb_par par;
-   int error = 0;
-
-   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));
+       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'.
+        */
 
-   /*
-    *    Get the User Defined Part of the Display
-    */
-
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
+static void ami_pan_var(struct fb_var_screeninfo *var)
 {
-   struct amiga_fb_par par;
-   int error = 0;
-
-   if (con == -1) {
-      amiga_fb_get_par(&par);
-      error = fbhw->encode_var(var, &par);
-   } else
-      *var = disp[con].var;
-   return(error);
-}
+       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 void amiga_fb_set_disp(int con)
-{
-   struct fb_fix_screeninfo fix;
-
-   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;
+       do_vmode_pan = 0;
+       ami_update_par();
+       do_vmode_pan = 1;
 }
 
+       /*
+        * Update hardware
+        */
 
-   /*
-    *    Set the User Defined Part of the Display
-    */
-
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
+static int ami_update_par(void)
 {
-   int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
-   if ((err = do_fb_set_var(var, con == currcon)))
-      return(err);
-   if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-      oldxres = disp[con].var.xres;
-      oldyres = disp[con].var.yres;
-      oldvxres = disp[con].var.xres_virtual;
-      oldvyres = disp[con].var.yres_virtual;
-      oldbpp = disp[con].var.bits_per_pixel;
-      disp[con].var = *var;
-      if (oldxres != var->xres || oldyres != var->yres ||
-          oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-          oldbpp != var->bits_per_pixel) {
-         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);
-}
+       struct amiga_fb_par *par = &currentpar;
+       short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
 
+       clk_shift = par->clk_shift;
 
-   /*
-    *    Get the Colormap
-    */
-
-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 (!(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;
+
+       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);
 
-   /*
-    *    Set the Colormap
-    */
+       if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
+               par->bplpt0 += par->next_line;
 
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-   int err;
-
-   if (!disp[con].cmap.len) {       /* no colormap allocated? */
-      if ((err = alloc_cmap(&disp[con].cmap, 1<<disp[con].var.bits_per_pixel,
-                            0)))
-         return(err);
-   }
-   if (con == currcon)              /* current console? */
-      return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
-   else
-      copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-   return(0);
+       return 0;
 }
 
+       /*
+        * Read a single color register and split it into
+        * colors/transparent. Return != 0 for invalid regno.
+        */
 
-   /*
-    *    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 int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp)
 {
-   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);
+       if (IS_AGA) {
+               if (regno > 255)
+                       return 1;
+       } else {
+               if (regno > 31)
+                       return 1;
+       }
+
+       *red = palette[regno].red;
+       *green = palette[regno].green;
+       *blue = palette[regno].blue;
+       return 0;
 }
 
 
-   /*
-    *    Amiga Frame Buffer Specific ioctls
-    */
+       /*
+        * 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 amiga_fb_ioctl(struct inode *inode, struct file *file,
-                          u_int cmd, u_long arg, int con)
+static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp)
 {
-   int i;
-   struct fb_fix_cursorinfo crsrfix;
-   struct fb_var_cursorinfo crsrvar;
-   struct fb_cursorstate crsrstate;
+#if defined(CONFIG_AMIFB_AGA)
+       u_short bplcon3 = currentpar.bplcon3;
 
-   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;
+       if (IS_AGA) {
+               if (regno > 255)
+                       return 1;
+       } else
 #endif
-   }
-   return(-EINVAL);
-}
+               if (regno > 31)
+                       return 1;
 
+       /*
+        * 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_AGA
-   /*
-    *    Hardware Cursor
-    */
+       palette[regno].red = red;
+       palette[regno].green = green;
+       palette[regno].blue = blue;
 
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
-{
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_get_fix_cursorinfo(fix, con));
-   return(-EINVAL);
+       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;
 }
 
-
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+static void ami_update_display(void)
 {
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_get_var_cursorinfo(var, con));
-   return(-EINVAL);
+       struct amiga_fb_par *par = &currentpar;
+
+       custom.bplcon1 = par->bplcon1;
+       custom.bpl1mod = par->bpl1mod;
+       custom.bpl2mod = par->bpl2mod;
+       custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
+       custom.ddfstop = ddfstop2hw(par->ddfstop);
 }
 
+       /*
+        * Change the video mode (called by VBlank interrupt)
+        */
 
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
-{
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_set_var_cursorinfo(var, con));
-   return(-EINVAL);
-}
+static void ami_init_display(void)
+{
+       struct amiga_fb_par *par = &currentpar;
+
+       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;
+
+       /*
+        * The minimum period for audio depends on htotal
+        */
 
+       amiga_audio_min_period = div16(par->htotal);
 
-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);
+       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
 }
 
+       /*
+        * (Un)Blank the screen (called by VBlank interrupt)
+        */
 
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
+static void ami_do_blank(void)
 {
-   if (boot_info.bi_amiga.chipset == CS_AGA)
-      return(aga_set_cursorstate(state, con));
-   return(-EINVAL);
-}
-#endif /* CONFIG_AMIFB_AGA */
+       struct amiga_fb_par *par = &currentpar;
+#if defined(CONFIG_AMIFB_AGA)
+       u_short bplcon3 = par->bplcon3;
+#endif
+       u_char red, green, blue;
 
+       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;
+}
 
-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
-};
+       /*
+        * Flash the cursor (called by VBlank interrupt)
+        */
 
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+{
+       struct amiga_fb_par *par = &currentpar;
+
+       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;
+}
 
-void amiga_video_setup(char *options, int *ints)
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
 {
-   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 */
+       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;
 
-#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:
-      ;
-   }
+       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;
 
-   /*
-    *    Initialization
-    */
+       state->xoffset = par->crsr.crsr_x;
+       state->yoffset = par->crsr.crsr_y;
+       state->mode = cursormode;
+       return 0;
+}
 
-struct fb_info *amiga_fb_init(long *mem_start)
+static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
 {
-   int err, tag, i;
-   struct fb_var_screeninfo *var;
-
-   /*
-    *    Check for a Graphics Board
-    */
+       struct amiga_fb_par *par = &currentpar;
 
-#ifdef CONFIG_FB_CYBER
-   if (amifb_Cyber)
-      return(Cyber_fb_init(mem_start));
-#endif /* CONFIG_FB_CYBER */
+       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;
+}
 
-   /*
-    *    Use the Builtin Chipset
-    */
+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;
 
-   if (!AMIGAHW_PRESENT(AMI_VIDEO))
-      return(NULL);
+       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);
+       }
+}
 
-#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 */
+       /*
+        * Initialise the Copper Initialisation List
+        */
 
-   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 */
+static void ami_init_copper(void)
+{
+       copins *cop = copdisplay.init;
+       u_long p;
+       int i;
 
-#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 */
+       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]);
+       }
 
-#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 */
+       (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
+       copdisplay.wait = cop;
+       (cop++)->l = CEND;
+       (cop++)->l = CMOVE(0, copjmp2);
+       cop->l = CEND;
 
-      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;
-   }
-
-   /*
-    *    Calculate the Pixel Clock Values for this Machine
-    */
-
-   __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");
-
-   /*
-    *    Replace the Tag Values with the Real Pixel Clock Values
-    */
-
-   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];
-      }
-   }
-
-   err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
-                              NUM_TOTAL_MODES, amiga_fb_predefined);
-   if (err < 0)
-      panic("Cannot register frame buffer");
-
-   fbhw->init();
-   check_default_mode();
-
-   if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer"))
-      panic("Couldn't add vblank interrupt");
-
-   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;
-
-   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]);
-
-   amiga_fb_get_var(&disp[0].var, -1);
-   amiga_fb_set_disp(-1);
-   do_install_cmap(0);
-   return(&fb_info);
+       custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
+       custom.copjmp1 = 0;
 }
 
-
-static int amifb_switch(int con)
+static void ami_reinit_copper(void)
 {
-   /* Do we have to save the colormap? */
-   if (disp[currcon].cmap.len)
-      do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
-   do_fb_set_var(&disp[con].var, 1);
-   currcon = con;
-   /* Install new colormap */
-   do_install_cmap(con);
-   return(0);
-}
+       struct amiga_fb_par *par = &currentpar;
 
+       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);
+}
 
-   /*
-    *    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.
-    */
+       /*
+        * Build the Copper List
+        */
 
-static int amifb_updatevar(int con)
+static void ami_build_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);
-}
+       struct amiga_fb_par *par = &currentpar;
+       copins *copl, *cops;
+       u_long p;
 
+       currentcop = 1 - currentcop;
 
-   /*
-    *    Blank the display.
-    */
-
-static void amifb_blank(int blank)
-{
-   do_blank = blank ? 1 : -1;
-}
+       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]);
 
-   /*
-    *    VBlank Display Interrupt
-    */
+       if (par->bplcon0 & BPC0_LACE) {
+               cops = copdisplay.list[currentcop][0];
 
-static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy)
-{
-   static int is_laced = 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
-   /*
-    *    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+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
+                       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);
+       ami_update_par();
+       ami_rebuild_copper();
 }
 
+       /*
+        * Rebuild the Copper List
+        *
+        * We only change the things that are not static
+        */
 
-   /*
-    *    Get a Video Modes
-    */
-
-static int get_video_mode(const char *name)
+static void ami_rebuild_copper(void)
 {
-   int i;
-
-   for (i = 1; i < NUM_PREDEF_MODES; i++)
-      if (!strcmp(name, amiga_fb_modenames[i]))
-         return(i);
-   return(0);
-}
-
+       struct amiga_fb_par *par = &currentpar;
+       copins *copl, *cops;
+       u_short line, h_end1, h_end2;
+       short i;
+       u_long p;
 
-   /*
-    *    Check the Default 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();
+
+       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;
 
-static void check_default_mode(void)
-{
-   struct fb_var_screeninfo var;
-
-   /* 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");
-
-found_video_mode:
-   amiga_fb_predefined[0] = var;
+       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;
+       }
 }
index 3bcd36d3775fe38506e063d936ac09f424d8a513..857b0b99a7c34457875ee5b2ade265c02a2cc037 100644 (file)
@@ -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>
 #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);
 
-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
-    };
+/* irq node variables for amiga interrupt sources */
+static irq_node_t *ami_irq_list[AMI_STD_IRQS];
 
-struct ciadata
-{
-    volatile struct CIA *ciaptr;
-    unsigned long      baseirq;
-} ciadata[2];
+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
+};
 
-/*
- * 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 short ami_ablecount[AMI_IRQS];
+
+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 @@ struct ciadata
  * 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)
+void amiga_init_IRQ(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;
-}
-
+       int i;
+
+       /* 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;
 
-/*
- * The builtin Amiga hardware interrupt handlers.
- */
+       /* turn off all interrupts and enable the master interrupt bit */
+       custom.intena = 0x7fff;
+       custom.intreq = 0x7fff;
+       custom.intena = IF_SETCLR | IF_INTEN;
 
-static void ami_int1 (int irq, struct pt_regs *fp, void *data)
-{
-    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;
-    }
-
-    /* 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;
-    }
+       cia_init_IRQ(&ciaa_base);
+       cia_init_IRQ(&ciab_base);
 }
 
-static void ami_int2 (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 (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);
+       if (!node->dev_id)
+               printk("%s: Warning: dev_id of %s is zero\n",
+                      __FUNCTION__, node->devname);
 
-       /* acknowledge */
-       custom.intreq = IF_PORTS;
-    }
-}
+       save_flags(flags);
+       cli();
 
-static void ami_int3 (int irq, struct pt_regs *fp, void *data)
-{
-    ushort ints = custom.intreqr & custom.intenar;
-
-    /* if a copper interrupt */
-    if (ints & IF_COPER) {
-       call_isr_list (IRQ_AMIGA_COPPER,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_COPER;
-    }
-
-    /* if a vertical blank interrupt */
-    if (ints & IF_VERTB) {
-       call_isr_list (IRQ_AMIGA_VERTB,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_VERTB;
-    }
-
-    /* if a blitter interrupt */
-    if (ints & IF_BLIT) {
-       call_isr_list (IRQ_AMIGA_BLIT,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_BLIT;
-    }
-}
+       cur = *list;
 
-static void ami_int4 (int irq, struct pt_regs *fp, void *data)
-{
-    ushort ints = custom.intreqr & custom.intenar;
-
-    /* if audio 0 interrupt */
-    if (ints & IF_AUD0) {
-       call_isr_list (IRQ_AMIGA_AUD0,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_AUD0;
-    }
-
-    /* if audio 1 interrupt */
-    if (ints & IF_AUD1) {
-       call_isr_list (IRQ_AMIGA_AUD1,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_AUD1;
-    }
-
-    /* if audio 2 interrupt */
-    if (ints & IF_AUD2) {
-       call_isr_list (IRQ_AMIGA_AUD2,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_AUD2;
-    }
-
-    /* if audio 3 interrupt */
-    if (ints & IF_AUD3) {
-       call_isr_list (IRQ_AMIGA_AUD3,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_AUD3;
-    }
+       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;
+               }
+       }
+
+       node->next = cur;
+       *list = node;
+
+       restore_flags(flags);
 }
 
-static void ami_int5 (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;
-
-    /* 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 a disk sync interrupt */
-    if (ints & IF_DSKSYN) {
-       call_isr_list (IRQ_AMIGA_DSKSYN,
-                      ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
-
-       /* acknowledge */
-       custom.intreq = IF_DSKSYN;
-    }
+       unsigned long flags;
+       irq_node_t *node;
+
+       save_flags(flags);
+       cli();
+
+       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__);
 }
 
-static void ami_int6 (int irq, struct pt_regs *fp, void *data)
+/*
+ * amiga_request_irq : add an interrupt service routine for a particular
+ *                     machine specific interrupt source.
+ *                     If the addition was successful, it returns 0.
+ */
+
+int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, const char *devname, void *dev_id)
 {
-    ushort ints = custom.intreqr & custom.intenar;
+       irq_node_t *node;
+
+       if (irq >= AMI_IRQS) {
+               printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
+               return -ENXIO;
+       }
 
-    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 (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;
+       }
 
-       /* acknowledge */
-       custom.intreq = IF_EXTER;
-    }
-}
+       /* enable the interrupt */
+       if (irq < IRQ_IDX(IRQ_AMIGA_PORTS)) 
+               custom.intena = IF_SETCLR | ami_intena_vals[irq];
 
-static void ami_int7 (int irq, struct pt_regs *fp, void *data)
-{
-    panic ("level 7 interrupt received\n");
+       return 0;
 }
 
-static void ami_intcia (int irq, struct pt_regs *fp, void *data)
+void amiga_free_irq(unsigned int irq, void *dev_id)
 {
-    /* check CIA interrupts */
-    struct ciadata *datap;
-    u_char cia_ints;
-
-    /* setup data correctly */
-    if (irq == IRQ_AMIGA_PORTS)
-           datap = &ciadata[0];
-    else
-           datap = &ciadata[1];
-
-    cia_ints = datap->ciaptr->icr;
-
-    /* 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 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);
-
-    /* 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);
-
-    /* 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);
-
-    /* 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);
+       if (irq >= AMI_IRQS) {
+               printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
+
+       if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+               cia_free_irq(&ciab_base, irq - IRQ_IDX(IRQ_AMIGA_CIAB), dev_id);
+               return;
+       }
+
+       if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+               cia_free_irq(&ciaa_base, irq - IRQ_IDX(IRQ_AMIGA_CIAA), dev_id);
+               return;
+       }
+
+       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];
+       }
 }
 
 /*
- * 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.
+ * 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.
  */
 
-int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
-                  *data, char *name)
+void amiga_enable_irq(unsigned int irq)
 {
-    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);
+       if (irq >= AMI_IRQS) {
+               printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
 
-    /* enable the interrupt */
-    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
+       if (ami_ablecount[irq]++)
+               return;
 
-    /* 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 (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+               cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
+                            (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB))));
+               return;
+       }
 
-    /* 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 (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+               cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
+                            (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA))));
+               return;
+       }
 
-    return 1;
+       /* enable the interrupt */
+       custom.intena = IF_SETCLR | ami_intena_vals[irq];
 }
 
-int amiga_remove_isr (unsigned long source, isrfunc isr, void *data)
+void amiga_disable_irq(unsigned int irq)
 {
-    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;
-    }
+       if (irq >= AMI_IRQS) {
+               printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
 
-    delete_isr (&ami_lists[amiga_source], isr, data);
+       if (--ami_ablecount[irq])
+               return;
 
-    if (ami_lists[amiga_source] == NULL) {
-       /* disable the interrupt */
-       custom.intena = ami_intena_vals[amiga_source];
+       if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) {
+               cia_able_irq(&ciab_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB)));
+               return;
+       }
 
-       /* 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 (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) {
+               cia_able_irq(&ciaa_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA)));
+               return;
+       }
 
-       /* 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);
-    }
+       /* disable the interrupt */
+       custom.intena = ami_intena_vals[irq];
+}
 
-    return 1;
+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);
 }
 
+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;
+
+       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;
+       }
+}
 
 /*
- * Enable/disable a particular machine specific interrupt source.
- * Note that this may affect other interrupts in case of a shared interrupt.
+ * The builtin Amiga hardware interrupt handlers.
  */
 
-void amiga_enable_irq(unsigned int source)
+static void ami_int1(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;
-    }
+       /* if serial transmit buffer empty, interrupt */
+       if (ints & IF_TBE) {
+               custom.intreq = IF_TBE;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_TBE), fp);
+       }
 
-    /* enable the interrupt */
-    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
+       /* if floppy disk transfer complete, interrupt */
+       if (ints & IF_DSKBLK) {
+               custom.intreq = IF_DSKBLK;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_DSKBLK), 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 software interrupt set, interrupt */
+       if (ints & IF_SOFT) {
+               custom.intreq = IF_SOFT;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_SOFT), fp);
+       }
+}
+
+static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
+{
+       unsigned short ints = custom.intreqr & custom.intenar;
+       static struct irq_server server = {0, 0};
 
-    /* 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 a blitter interrupt */
+       if (ints & IF_BLIT) {
+               custom.intreq = IF_BLIT;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp);
+       }
+
+       /* if a copper interrupt */
+       if (ints & IF_COPER) {
+               custom.intreq = IF_COPER;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_COPPER), fp);
+       }
 
+       /* if a vertical blank interrupt */
+       if (ints & IF_VERTB)
+               amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server);
 }
 
-void amiga_disable_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_disable_irq: Unknown interrupt source %d\n", source);
-       return;
-    }
+       /* if audio 0 interrupt */
+       if (ints & IF_AUD0) {
+               custom.intreq = IF_AUD0;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD0), fp);
+       }
 
-    /* disable the interrupt */
-    custom.intena = ami_intena_vals[amiga_source];
+       /* if audio 1 interrupt */
+       if (ints & IF_AUD1) {
+               custom.intreq = IF_AUD1;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD1), 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 audio 2 interrupt */
+       if (ints & IF_AUD2) {
+               custom.intreq = IF_AUD2;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD2), 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 audio 3 interrupt */
+       if (ints & IF_AUD3) {
+               custom.intreq = IF_AUD3;
+               amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD3), fp);
+       }
+}
 
+static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
+{
+       unsigned short ints = custom.intreqr & custom.intenar;
+
+       /* 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 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");
+}
 
-int amiga_get_irq_list( char *buf, int len )
-{      int                     i;
-    isr_node_t *p;
+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
+};
 
-       for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
-               if (!ami_lists[i])
+int amiga_get_irq_list(char *buf)
+{
+       int i, len = 0;
+       irq_node_t *node;
+
+       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;
 }
index 59aafcacf0b938cca8146c25524b96e0bd14e946..d0f01dc70953935161f911838013d254d45ff5c5 100644 (file)
@@ -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
 #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 @@ static u_short amiplain_map[NR_KEYS] = {
        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 @@ static u_short amishift_map[NR_KEYS] = {
        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 @@ static u_short amialtgr_map[NR_KEYS] = {
        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 @@ static u_short amictrl_map[NR_KEYS] = {
        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 @@ static u_short amishift_ctrl_map[NR_KEYS] = {
        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 @@ static u_short amialt_map[NR_KEYS] = {
        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 @@ static u_short amictrl_alt_map[NR_KEYS] = {
        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_delay = DEFAULT_KEYB_REP_DELAY;
 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();
+    unsigned long flags;
+    save_flags(flags);
+    cli();
 
-       pt_regs = NULL;
+    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);
+    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 @@ static void keyboard_interrupt (int irq, struct pt_regs *fp, void *dummy)
 
     /* 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 @@ int amiga_keyb_init (void)
     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 @@ int amiga_keyb_init (void)
     /*
      * 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 );
 }
index db62a51f0baefd92bfa6ee043fff1922a9d15ca2..8b25b14534835d65e3a0f9eeb93156b8992a85f7 100644 (file)
@@ -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[] = {
index 5d0e7d68f04d16444d39522769c69ac2b095b481..28fb0c000f2c9b0addd0e44affc2b10bf4487bca 100644 (file)
@@ -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 @@ struct chip_desc {
 #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 @@ void amiga_chip_init (void)
   
   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 @@ void *amiga_chip_alloc (long size)
        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 @@ void *amiga_chip_alloc (long size)
        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 @@ void amiga_chip_free (void *ptr)
        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 --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
new file mode 100644 (file)
index 0000000..6c9a01c
--- /dev/null
@@ -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;
+}
index 80b8621d5eddc2b6232daa800ab9a8fc6401ff8f..7026c488a9e84b119b8e5be7d49b495f7905119d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/amiga/config.c
+ *  linux/arch/m68k/amiga/config.c
  *
  *  Copyright (C) 1993 Hamish Macdonald
  *
 #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 @@ u_long amiga_colorclock;
 
 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 @@ void config_amiga(void)
       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 @@ void config_amiga(void)
   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 @@ void config_amiga(void)
 #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 *))
 {
-
-#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;
+       jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
+
+       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 @@ void amiga_sched_init (isrfunc timer_routine)
 /* 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;
+       /* read CIA B timer A current value */
+       hi  = ciab.tahi;
+       lo  = ciab.talo;
+       hi2 = ciab.tahi;
 
-    if (hi != hi2) {
-       lo = ciab.talo;
-       hi = hi2;
-    }
+       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 @@ void amiga_reset (void)
   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
      */
index 9d24b227837286995a5e3c93026acd63f132fd25..0b8a0f8dfafecdc90048cc269416d10a34abf6d5 100644 (file)
 #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 @@ for (i = 0; i < 256; i++)
   }
 
 *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 @@ if (Cyberfb_Cyber8)
 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 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 
    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;
index 722bfda941893b5123e1cc86ee4f034c858335f5..3c32ffacf601bdd5d8d3b1b2c628b72044b3f926 100644 (file)
@@ -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 @@ static struct symbol_table mach_amiga_symbol_table = {
   /*
    * 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),
index e3677cbb3604b92a5e1da448feddd55eaff54e1a..d27afe4b16c43e5301edaeecf6ba4029835e8019 100644 (file)
@@ -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 @@ struct GVP_Product {
     *             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 @@ BEGIN_PROD(COMMODORE)
    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 @@ BEGIN_PROD(AMERISTAR)
 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 @@ BEGIN_PROD(CSA)
    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 @@ BEGIN_GVP_PROD
    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 @@ BEGIN_PROD(PPI)
    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 @@ BEGIN_PROD(CHECKPOINT)
    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 @@ BEGIN_PROD(ADV_SYS_SOFT)
    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 @@ BEGIN_PROD(HYDRA_SYSTEMS)
    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 @@ BEGIN_PROD(SW_RESULT_ENTS)
    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 @@ BEGIN_PROD(UTILITIES_ULTD)
    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 @@ BEGIN_PROD(MACROSYSTEMS2)
    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 @@ static int identify(int devnum, char *buf)
                   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;
index c84cb6cde0099f8d5714242b05b16402fda50b10..77324bc1026763fc7d1a402cce5e7b0213c22d00 100644 (file)
@@ -11,7 +11,6 @@ EXTRA_CFLAGS := -Wa,-m68030
 
 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
index f01a7072fd28f5bdec8b087416e422a855ee61c9..8156c61a4e49185a418a0fdc892b2c48c4546d86 100644 (file)
@@ -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>
 #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 sttt_xres_virtual=640,sttt_yres_virtual=400;
 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 @@ extern unsigned short packed16_cmap[16];
  *   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 @@ static int tt_decode_var( struct fb_var_screeninfo *var,
        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 @@ static int tt_decode_var( struct fb_var_screeninfo *var,
                        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 @@ static int tt_encode_var( struct fb_var_screeninfo *var,
        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 long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000;
 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 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
        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_encode_fix( struct fb_fix_screeninfo *fix,
 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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
                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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
        {       /* 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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
                        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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
        /*********************
        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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
         * 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 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
 
   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 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
                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_set_par( struct atari_fb_par *par )
 }
 
 
-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 @@ static void falcon_vbl_switcher( int irq, struct pt_regs *fp, void *dummy )
                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 @@ static int falcon_pan_display( struct fb_var_screeninfo *var,
                                                           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 @@ static int falcon_blank( int blank_mode )
 {
 /* ++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 @@ static int stste_encode_fix( struct fb_fix_screeninfo *fix,
                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 @@ static int stste_decode_var( struct fb_var_screeninfo *var,
        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 @@ static int stste_decode_var( struct fb_var_screeninfo *var,
                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 @@ static int stste_encode_var( struct fb_var_screeninfo *var,
        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 void set_screen_base(unsigned long s_base)
 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 @@ atari_fb_set_disp(int con)
 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 @@ atafb_switch(int con)
        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 @@ atari_fb_init(long *mem_start)
 #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 @@ atari_fb_init(long *mem_start)
                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 @@ void atari_video_setup( char *options, int *ints )
        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))
index 274824d9a022c663af35d194618d9836f57d0e13..4a7fe4500149447ab511775e8bf84c05e24afa05 100644 (file)
@@ -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
  *  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.
 #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>
 
 
  * 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
 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 irqhandler irq_handler[NUM_INT_SOURCES];
 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 @@ static int next_free_vme_vec = VME_SOURCE_BASE;
          /* 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 @@ static int next_free_vme_vec = VME_SOURCE_BASE;
 #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 @@ asmlinkage void IRQ_NAME(n);                                                 \
 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 @@ void atari_fast_prio_irq_dummy (void) {
 __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 @@ asmlinkage void falcon_hblhandler(void);
 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 @@ asmlinkage void bad_interrupt(void);
 extern void atari_microwire_cmd( int cmd );
 
 /*
- * void atari_init_INTS (void)
+ * void atari_init_IRQ (void)
  *
  * Parameters: None
  *
@@ -337,7 +335,7 @@ extern void atari_microwire_cmd( int cmd );
  * the atari IRQ handling routines.
  */
 
-void atari_init_INTS(void)
+void atari_init_IRQ(void)
 {
        int i;
 
@@ -353,9 +351,9 @@ void atari_init_INTS(void)
 #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 @@ void atari_init_INTS(void)
 #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 @@ void atari_init_INTS(void)
 }
 
 
-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 (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(source)) {
-               printk ("atari_add_isr: Unknown irq %ld requested from %s\n",
-                               source, name );
-               return( 0 );
+       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 @@ int atari_remove_isr(unsigned long source, isrfunc isr, void *data)
 
 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;
 }
index f1e2124eae0e71674025d58571325c69d6244e27..95cc0245f225aa30071cee126bef97dd4540fe36 100644 (file)
 #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 @@ void (*atari_MIDI_interrupt_hook) (void);
 /* Hook for mouse driver */
 void (*atari_mouse_interrupt_hook) (char *);
 
-#define ATAKEY_CAPS    (58)
 #define BREAK_MASK     (0x80)
 
 /*
@@ -83,6 +81,11 @@ void (*atari_mouse_interrupt_hook) (char *);
  *      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 @@ static u_short ataplain_map[NR_KEYS] = {
        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 @@ static u_short atashift_map[NR_KEYS] = {
        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 @@ static u_short atactrl_map[NR_KEYS] = {
        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 @@ static u_short atashift_ctrl_map[NR_KEYS] = {
        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 @@ static u_short ataalt_map[NR_KEYS] = {
        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 @@ static u_short atashift_alt_map[NR_KEYS] = {
        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 @@ static u_short atactrl_alt_map[NR_KEYS] = {
        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 @@ static u_short atashift_ctrl_alt_map[NR_KEYS] = {
        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 @@ static void atakeyb_rep( unsigned long ignore )
 {
        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 @@ static void atakeyb_rep( unsigned long ignore )
                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 @@ static void atakeyb_rep( unsigned long ignore )
  * 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 @@ static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
        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 @@ static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
     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 @@ static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
                    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 @@ static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
        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 @@ int atari_keyb_init(void)
     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 --git a/arch/m68k/atari/atari.mup b/arch/m68k/atari/atari.mup
deleted file mode 100644 (file)
index 1a62330..0000000
+++ /dev/null
@@ -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
index 59755fff8153e2a0febe754d5eb6e6dbd318d371..33f7f79c6b7dfc2d1ea3618502d73288d64ef18d 100644 (file)
@@ -17,17 +17,16 @@ for more details.
 #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 @@ void atari_mksound (unsigned int count, unsigned int ticks)
        }
        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;
 
index 24b6df808f733fadde1fc91e44b7f1ce2a45a2da..b4460c46578ff476b117e20162ec3e124ef97493 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  linux/atari/config.c
+ *  linux/arch/m68k/atari/config.c
  *
- *  Copyright (C) 1994 Bj\94rn Brauel
+ *  Copyright (C) 1994 Bjoern Brauel
  *
  *  5/2/94 Roman Hodek:
  *    Added setting of time_adj to get a better clock.
 #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>
 #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 @@ void config_atari(void)
     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 @@ void config_atari(void)
     }
     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 @@ void config_atari(void)
      * 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 config_atari(void)
     }
 }
 
-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 @@ void atari_reset (void)
         "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"
index 65fd526d34e2f044970980664955cf2be680a608..1c51ec3e4777103597428b981015e5d7a9ac78a3 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
@@ -13,6 +12,7 @@ static struct symbol_table mach_atari_symbol_table = {
 
        X(is_medusa),
        X(atari_register_vme_int),
+       X(atari_unregister_vme_int),
        X(stdma_lock),
        X(stdma_release),
        X(stdma_others_waiting),
index ea4db7f6e81214164c98270f904369ab4ad900bb..af4a6c7b63543dcd0b344243eb9d01dc9998586a 100644 (file)
@@ -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 @@ static struct wait_queue *stdma_wait = NULL;  /* wait queue for ST-DMA */
 
 /***************************** 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 @@ static void stdma_int (int irq, struct pt_regs *fp, void *dummy);
  *
  */
 
-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 @@ void stdma_lock(isrfunc isr, void *data)
                sleep_on(&stdma_wait);
 
        stdma_locked   = 1;
-       stdma_isr      = isr;
+       stdma_isr      = handler;
        stdma_isr_data = data;
        restore_flags(oldflags);
 }
@@ -174,8 +175,8 @@ int stdma_islocked(void)
 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 @@ void stdma_init(void)
  *
  */
 
-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);
 }
index 31b5e470a3c8bc5066ea707a2cccc89399e5ca2a..a82988daed08724dc4343509e803765f0c89af5a 100644 (file)
@@ -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>
index 83c70048bafa18db1dc54538c28356eb09f603ad..e67a9c4d1f720800a07a1f3f5742f643e1c439c4 100644 (file)
@@ -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:
index 8f9ced5619965ef7c66aa4cfb51c4066867e7ef3..20ca0621f9c1a3d9e3e48af2fc8c6bcd3932dc70 100644 (file)
@@ -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
 #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 */
+/* required Linux/m68k include files */
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+
+/* Amiga bootstrap include files */
+#include "linuxboot.h"
 #include "bootstrap.h"
 
-/* required Linux/68k include files */
-#include <linux/a.out.h>
-#include <asm/bootinfo.h>
 
-/* temporary stack size */
-#define TEMP_STACKSIZE 256
+/* Library Bases */
+extern const struct ExecBase *SysBase;
+const struct ExpansionBase *ExpansionBase;
+const struct GfxBase *GfxBase;
 
-/* Exec Base */
-extern struct ExecBase *SysBase;
+static const char *memfile_name = NULL;
 
-extern char *optarg;
+static int model = AMI_UNKNOWN;
 
-struct exec kexec;
-char *memptr;
-u_long start_mem;
-u_long mem_size;
-u_long rd_size;
+static const char *ProgramName;
 
-struct ExpansionBase *ExpansionBase;
-struct GfxBase *GfxBase;
+struct linuxboot_args args;
 
-struct bootinfo bi;
-u_long bi_size = sizeof bi;
 
-caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
+    /*
+     *  Function Prototypes
+     */
 
-void usage(void)
+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);
+
+
+static void Usage(void)
 {
-       fprintf (stderr, "Usage:\n"
-                "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
-                " [option...]\n");
-       exit (EXIT_FAILURE);
+    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);
 }
 
-/*
- * 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();
-
-
-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("\fLinux/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++;
-
-               /* get next device */
-               cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
-       }
-
-       /* 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; */
-               }
-       }
-
-       CloseLibrary((struct Library *)ExpansionBase);
-
-       /*
-        * 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);
-           }
-
-           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);
-
-           if (i != bi.num_memory && i > 0)
-               bi.num_memory = i;
-       }
-
-       /* 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);
-       }
-
-       /* 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 %08lx\n", start_mem);
-
-       /* 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);
-       }
-
-       /* verify that there is enough Fast RAM */
-       if (fast_total < 2*1024*1024) {
-               puts("\nNot enough Fast RAM in this system.  Aborting...");
-               exit(10);
-       }
-
-       /* 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);
-       }
-
-       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);
+    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;
-         default:
-           fprintf (stderr, "Wrong magic number %lo in kernel header\n",
-                    N_MAGIC(kexec));
-           exit (EXIT_FAILURE);
+    }
+    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;
+
+    /* Do The Right Stuff */
+    linuxboot(&args);
+
+    CloseLibrary((struct Library *)GfxBase);
+    CloseLibrary((struct Library *)ExpansionBase);
+
+    /* if we ever get here, something went wrong */
+    exit(EXIT_FAILURE);
+}
 
-       /* 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);
-       }
 
-       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);
-       }
+    /*
+     *  Routines needed by linuxboot
+     */
 
-       /* 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);
-
-       /* 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);
-       }
-
-       /* 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 void Puts(const char *str)
+{
+    fputs(str, stderr);
+}
 
-       /* 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 long GetChar(void)
+{
+    return(getchar());
+}
 
-       /* 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 void PutChar(char c)
+{
+    fputc(c, stderr);
+}
 
-       /* wait for things to settle down */
-       sleep(2);
-
-       /* 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 void Printf(const char *fmt, ...)
+{
+    va_list args;
 
-       /* 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;
-       }
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
 
-       /* 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 int Open(const char *path)
+{
+    return(open(path, O_RDONLY));
+}
 
-       if (GfxBase) {
-               /* set graphics mode to a nice normal one */
-               LoadView (NULL);
-               CloseLibrary ((struct Library *)GfxBase);
-       }
+static int Seek(int fd, int offset)
+{
+    return(lseek(fd, offset, SEEK_SET));
+}
 
-       Disable();
 
-       /* Turn off all DMA */
-       custom.dmacon = DMAF_ALL | DMAF_MASTER;
+static int Read(int fd, char *buf, int count)
+{
+    return(read(fd, buf, count));
+}
 
-       /* turn off caches */
-       CacheControl (0L, ~0L);
+static void Close(int fd)
+{
+    close(fd);
+}
 
-       /* Go into supervisor state */
-       SuperState ();
+static int FileSize(const char *path)
+{
+    int fd, size = -1;
 
-       /* setup stack */
-       change_stack ((char *) stack + TEMP_STACKSIZE);
+    if ((fd = open(path, O_RDONLY)) != -1) {
+        size = lseek(fd, 0, SEEK_END);
+        close(fd);
+    }
+    return(size);
+}
 
-       /* turn off any mmu translation */
-       disable_mmu ();
+static void Sleep(u_long micros)
+{
+    struct MsgPort *TimerPort;
+    struct timerequest *TimerRequest;
+
+    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);
+    }
+}
 
-       /* execute the copy-and-go code (from CHIP RAM) */
-       startfunc();
 
-       /* NOTREACHED */
+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;
+
+   return(TRUE);
 }
index 449b18b83bfe1c261f1fc3cb0d9826588c1d5f95..d7a5c44fd805db2223b812599a2fb961a836905f 100644 (file)
@@ -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
 **
 */
 
-#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      */
-};
-
-#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 MsgPort {
+    u_char fill1[15];
+    u_char mp_SigBit;
+    u_char fill2[18];
 };
 
-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;
+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];
 };
 
-#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
- */
+#define IOF_QUICK      (1<<0)
 
-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
+#define UNIT_VBLANK    1
+#define TR_ADDREQUEST  9
 
-#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)
 
 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)
+static __inline void CloseLibrary(struct Library *library)
 {
-  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");
+    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 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)
-{
-  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;
-}
-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 --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
new file mode 100644 (file)
index 0000000..975868c
--- /dev/null
@@ -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 --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
new file mode 100644 (file)
index 0000000..2331a99
--- /dev/null
@@ -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 --git a/arch/m68k/boot/atari/Makefile b/arch/m68k/boot/atari/Makefile
deleted file mode 100644 (file)
index c60a24d..0000000
+++ /dev/null
@@ -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 --git a/arch/m68k/boot/atari/bootp.c b/arch/m68k/boot/atari/bootp.c
new file mode 100644 (file)
index 0000000..db4fc28
--- /dev/null
@@ -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 --git a/arch/m68k/boot/atari/bootp.h b/arch/m68k/boot/atari/bootp.h
new file mode 100644 (file)
index 0000000..02988ed
--- /dev/null
@@ -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 */
+
index fb4055cf72cf11fcd7e8b11e6b4200883038e3cc..dbf5fada039f42e2f08e412bee19f61dc4c0db23 100644 (file)
@@ -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 @@ int test_medusa( void )
 }
 
 
+/* 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 @@ void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
 #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 @@ int main(int argc, char *argv[])
     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 @@ int main(int argc, char *argv[])
            break;
 #ifdef USE_BOOTP
          case 'b':
-           prefer_bootp = 1;
+           prefer_bootp = 0;
            break;
 #endif
          case '?':
@@ -370,8 +438,7 @@ int main(int argc, char *argv[])
     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 @@ int main(int argc, char *argv[])
                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 @@ int main(int argc, char *argv[])
                        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 @@ int main(int argc, char *argv[])
       }
     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 @@ int main(int argc, char *argv[])
       }
     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 @@ int main(int argc, char *argv[])
            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 @@ int main(int argc, char *argv[])
     {
        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 @@ int main(int argc, char *argv[])
                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 --git a/arch/m68k/boot/atari/ethlance.c b/arch/m68k/boot/atari/ethlance.c
new file mode 100644 (file)
index 0000000..3b248c4
--- /dev/null
@@ -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 --git a/arch/m68k/boot/atari/ethlance.h b/arch/m68k/boot/atari/ethlance.h
new file mode 100644 (file)
index 0000000..4f9c902
--- /dev/null
@@ -0,0 +1,7 @@
+
+#ifndef _ethlance_h
+#define _ethlance_h
+
+extern ETHIF_SWITCH LanceSwitch;
+
+#endif /* _ethlance_h */
index bb0f19aea634124ded37f5446a913b62cdae5afe..8a82be452d23ce183b3bfa35330b8f59e26bb7a6 100644 (file)
@@ -4,6 +4,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
@@ -14,22 +19,48 @@ fi
 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 @@ comment 'Floppy, IDE, and other block devices'
 
 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 @@ tristate 'SCSI support' CONFIG_SCSI
 
 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 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
 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 'Dummy net driver support' CONFIG_DUMMY
 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 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
 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 @@ fi
 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
index 3bfe4c34d90bfd0e22eafb1a75aba0712fadc560..6c2126a1d3639dce0a772277e350ae02777ea4fe 100644 (file)
@@ -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
index cf6d2e5f421e710cf414084630e5812d33ab0316..32c5752c0f64093557c3046e36e6f32b23d933e2 100644 (file)
@@ -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_short expand2w(u_char c);
 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 @@ static u_long fbcon_startup(u_long kmem_start, char **display_desc)
 #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 int fbcon_cursor(struct vc_data *conp, int mode)
 }
 
 
-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 @@ static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
 {
        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 @@ static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
                /* 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 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
 {
        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 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
                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 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
   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) &&
index 959b9ab58eb3effa0dc18bd2d1949dde86f5d04e..934a0bc70361b71d231bac3514101790075ce605 100644 (file)
@@ -12,8 +12,8 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
+#include <asm/setup.h>
 #include <asm/font.h>
-#include <asm/bootinfo.h>
 
 
    /*
index 3650350eb5b7ed16283cfcbef0f17cd611272159..31f9c3690507370c99d66e65e22175584a1bd457 100644 (file)
@@ -2,6 +2,11 @@
 # Automatically generated make config: don't edit
 #
 
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
 #
 # Loadable module support
 #
 # 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_BLK_DEV_SR=y
 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_A3000_SCSI=y
 # 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_NFS_FS=y
 # 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
 
 #
index b5a4a6e290b1c186fda19bcebbb32b283193739f..4e4eab64ef436a03c6a15cebc242cc5c2473f341 100644 (file)
 |
 |      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 @@ real_dz:
        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 @@ not_b1232:
 
 real_inex:
 
-       addl            #1,siginex              |for standalone testing
-
        link            %a6,#-LOCAL_SIZE
        fsave           -(%sp)
 not_fmt40:
@@ -203,8 +190,6 @@ ovfl:
        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 @@ unfl:
        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 @@ real_snan:
        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 @@ real_operr:
        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 @@ real_bsun:
        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 @@ fline:
        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
@@ -387,9 +358,6 @@ real_unsupp:
        frestore        (%sp)+
        unlk            %a6
 
-       addl            #1,sigunsupp            |for standalone testing
-
-
        SAVE_ALL
        moveq   #-1,%d0
        movel   %d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
index b20e523bcd68c04fa465057ff0a512a9bb042b64..fe66cf033c8c26e9a17516429fd0225179b2c9eb 100644 (file)
@@ -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
 
index c087fb12e77e3d7c688234dfbca85c54a145173b..96939b0c49e5eaa5a7228dc301c5c7c1118ae927 100644 (file)
@@ -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 @@ _060_real_ovfl:
        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 @@ _060_real_unfl:
        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 @@ _060_real_operr:
        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 @@ _060_real_snan:
        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 @@ _060_real_dz:
        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 @@ _060_real_inex:
        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 @@ _060_real_inex:
 |
        .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 @@ _060_real_bsun:
 | 
        .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 @@ _060_real_fline:
        .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 @@ _060_real_fpu_disabled:
 |
        .global         _060_real_trap
 _060_real_trap:
-       rte
+       bral            SYMBOL_NAME(trap)       | jump to trap handler
 
 |############################################################################
 
index a355e2904bf3bf82d720f6d6d1fbf00256b52170..5940a374aec6a0d2a996e1f6a631febb884918e6 100644 (file)
 |      (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        #
 | 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 @@ _060_isp_done:
 | 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 @@ _060_real_chk:
 |      *      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 @@ real_chk_end:
 | 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 @@ _060_real_divbyzero:
 |      *      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
 
 |##########################
 
@@ -176,6 +202,9 @@ _060_real_cas2:
 |      d1 = `xxxxxxff -> longword; `xxxxxx00 -> word
 | 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:
@@ -194,6 +223,9 @@ _060_real_lock_page:
 |      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
index 67642fe160ec35208c020ae0fedcf1ef85c92bb4..3e0e307015c924610317130ab0cbe55fa741f7e9 100644 (file)
@@ -32,6 +32,7 @@
 |      - example "Call-Out"s required by both the ISP and FPSP.
 |
 
+#include <linux/linkage.h>
 
 |################################
 | EXAMPLE CALL-OUTS            #
 | 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 @@ user_read:
 _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
 
 |
@@ -172,23 +171,30 @@ dmrbs:    clr.l           %d0                     | clear whole longword
 | OUTPUTS:
 |      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
 
 |
@@ -202,22 +208,28 @@ dmrws:    clr.l           %d0                     | clear whole longword
 | OUTPUTS:
 |      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 @@ dmrls:    move.l          (%a0),%d0               | fetch super longword
 _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 @@ dmwbs:    move.b          %d0,(%a0)               | store super byte
 _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 @@ dmwws:    move.w          %d0,(%a0)               | store super word
 _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 @@ imrls:     move.l          (%a0),%d0               | fetch super longword
 | 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 @@ _copyout:
        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 @@ _copyin:
        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 @@ morein:
 |
        .global         _060_real_trace
 _060_real_trace:
-       rte
+       bral    SYMBOL_NAME(trap)
 
 |
 | _060_real_access():
@@ -429,4 +373,4 @@ _060_real_trace:
 |
        .global         _060_real_access
 _060_real_access:
-       rte
+       bral    SYMBOL_NAME(buserr)
index 1d37ffa4ac4a8cfe1924a693e00453f5ed306803..339e1b5db718edafaeb38caa25369c1df4ef3cbc 100644 (file)
@@ -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
 
index 5075a5ae5feba54be4a88336c9eef5901a14a280..e8888387e0375773fa86c026a8edb06689ac5baa 100644 (file)
@@ -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 @@ static unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
        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 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 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 @@ static void gotoxy(int currcons, int new_x, int new_y)
                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 @@ static void set_mode(int currcons, int on_off)
                                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 @@ static void setterm_command(int currcons)
                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 @@ static int con_write(struct tty_struct * tty, int from_user,
                    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 @@ static int con_write(struct tty_struct * tty, int from_user,
                                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 @@ static int con_write(struct tty_struct * tty, int from_user,
                                    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 @@ unsigned long con_init(unsigned long kmem_start)
        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 @@ void do_blank_screen(int nopowersave)
 
        /* 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 @@ int con_open(struct tty_struct *tty, struct file * filp)
 /*
  * 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();
-
-       if (set)
-               memcpy_fromfs (charmap, arg, cmapsz);
-       else
-               memcpy_tofs (arg, charmap, cmapsz);
-
-       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();
+       size = ch512 ? 2*cmapsz : cmapsz;
 
-       return 0;
+       charmap = (char *)kmalloc(size, GFP_USER);
+
+       if (set){
+               memcpy_fromfs(charmap, arg, size);
+
+               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 @@ void set_palette(void)
  * 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 @@ int con_adjust_height(unsigned long fontheight)
 
 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)
index b7dea79e176652135e33f653ef5e8ad97ea60afc..396078e099f67ca77b577811061159376b796dce 100644 (file)
@@ -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
  *
  */
 
  */
 
 #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_PRIORITY      =  8
 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 @@ ENTRY(system_call)
        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 @@ ENTRY(system_call)
        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 @@ SYMBOL_NAME_LABEL(ret_from_exception)
        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 @@ SYMBOL_NAME_LABEL(inthandler)
        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(inthandler)
 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 @@ ENTRY(sys_sigreturn)
        rts
 
 LFLUSH_I_AND_D = 0x00000808
-LBI_CPU = 4
 LTSS_KSP       = 0
 LTSS_USP       = 4
 LTSS_SR                = 8
@@ -345,17 +324,16 @@ LTSS_FPCTXT       = 32
 
 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 @@ SYMBOL_NAME_LABEL(resume)
        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 @@ SYMBOL_NAME_LABEL(resume)
 
        /* 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 (a1 contains new task) */
+       movel   %a1,SYMBOL_NAME(current_set)
+       addl    %d1,%a1
 
-       /* get pointer to tss struct (d1 contains new task) */
-       movel   %d1,SYMBOL_NAME(current_set)
-       movel   %d1,%a0
-       addl    %a1,%a0
+       /* 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
+       tstl    SYMBOL_NAME(m68k_is040or060)
        bnes    1f
-       btst    #3,SYMBOL_NAME(boot_info)+LBI_CPU+3
-       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 @@ SYMBOL_NAME_LABEL(resume)
        .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
 
index 795d7466e8acd296354045f68587b9bc2d7a8f73..354c17eea75fd29f499cfda3a81f1361df86b7a6 100644 (file)
@@ -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 @@ ENTRY(_start)
        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 @@ Lmapphys:
  * 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 @@ Lmapphys:
 
        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 @@ Lmapphys:
         */
        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 @@ Lmapphysnotamiga:
         * 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 @@ Latarimmu68040:
        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 @@ Lshowtest:
        putc('=')
        putn(%a1)
 
-       ptestr  #5,%a1@,#7,%a0
+       .long   0xf0119f15              | ptestr        #5,%a1@,#7,%a0
 
        putc('D')
        putc('A')
@@ -1110,7 +1117,7 @@ Lshowtest:
        putc('S')
        putc('=')
        lea     %pc@(Lmmu),%a0
-       pmove   %psr,%a0@
+       .long   0xf0106200              | pmove         %psr,%a0@
        clrl    %d7
        movew   %a0@,%d7
        jbsr    Lserial_putnum
index 885ced14de81610b738fe87f3af88261c03909be..8656b2979dd464ed3710e3c6aa5531658b7a0a8b 100644 (file)
@@ -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
  *           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>
 #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 @@ unsigned long interrupt_stack[PAGE_SIZE/sizeof(long)];
 
 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;
-
-    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;
+       int i;
+
+       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 (np = nodes; np < &nodes[NUM_ISR_NODES]; np++)
-       if (np->isr == NULL)
-           return np;
+       for (i = 0; i < NUM_IRQ_NODES; i++)
+               nodes[i].handler = NULL;
 
-    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 (irq & IRQ_MACHSPEC)
+               return mach_request_irq(IRQ_IDX(irq), handler, flags, devname, dev_id);
 
-    if (source < IRQ1 || source > IRQ7) {
-       printk ("remove_isr: Incorrect IRQ source %ld\n", source);
-       return 0;
-    }
-
-    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 (irq & IRQ_MACHSPEC) {
+               mach_free_irq(IRQ_IDX(irq), dev_id);
+               return;
+       }
 
-       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 < IRQ1 || irq > IRQ7) {
+               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
                return;
        }
 
-       kstat.interrupts[level]++;      
-       call_isr_list (level, isr_list[level-1], regs);
-}
+       if (irq_list[irq].dev_id != dev_id)
+               printk("%s: Removing probably wrong IRQ %d from %s\n",
+                      __FUNCTION__, irq, irq_list[irq].devname);
 
-int request_irq(unsigned int irq,
-               void (*handler)(int, void *, struct pt_regs *),
-               unsigned long flags, const char * devname, void *dev_id)
-{
-       return -EINVAL;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
+       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 @@ void free_irq(unsigned int irq, void *dev_id)
  */
 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)
+{
+       if ((irq & IRQ_MACHSPEC) && mach_enable_irq)
+               mach_enable_irq(IRQ_IDX(irq));
 }
 
-void enable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq)
 {
-       if ((irq_nr & IRQ_MACHSPEC) && mach_enable_irq)
-               mach_enable_irq(irq_nr);
+       if ((irq & IRQ_MACHSPEC) && mach_disable_irq)
+               mach_disable_irq(IRQ_IDX(irq));
 }
 
-void disable_irq(unsigned int irq_nr)
+asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
 {
-       if ((irq_nr & IRQ_MACHSPEC) && mach_disable_irq)
-               mach_disable_irq(irq_nr);
+       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;
 }
index 302346a05b7b19985ae66d42c5270ee6d5ee322e..bee06dccee0301da340a9b04fa2dc9564fbe5259 100644 (file)
@@ -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 @@ static struct symbol_table arch_symbol_table = {
        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 @@ static struct symbol_table arch_symbol_table = {
           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>
 };
 
index 988d0bd4233f1a923ebd794707bebe039b217767..8e6517aa9e11dd7ed8fd1a9b4aa77a8fba2afdfd 100644 (file)
@@ -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 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 
        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 @@ int dump_fpu (struct user_m68kfp_struct *fpu)
 
   /* 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])
index 3571cf22ffab461c21ac720aa3b260bd68d4777b..5fbb279e33bdafba1139545981335b57b31c9f34 100644 (file)
@@ -198,6 +198,7 @@ repeat:
 /* 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 @@ static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigne
        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)
index 02827736eb4c333b7a52275225fb226308b8e020..58987d1cce2d312d779a746132e931521c3b1062 100644 (file)
@@ -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 @@ static void dummy_waitbut(void)
 {
 }
 
-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 @@ void (*mach_floppy_eject) (void) = NULL;
 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 @@ void setup_arch(char **cmdline_p,
        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 */
@@ -178,6 +181,11 @@ void setup_arch(char **cmdline_p,
            case MACH_MAC:
                config_mac();
                break;
+#endif
+#ifdef CONFIG_SUN3
+           case MACH_SUN3:
+               config_sun3();
+               break;
 #endif
            default:
                panic ("No configuration setup");
@@ -191,39 +199,29 @@ void setup_arch(char **cmdline_p,
 #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 @@ int get_cpuinfo(char * buffer)
     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)
index e701861004b6a0b7569c8fb7958de0a30c7150d3..f85992a82eb1a377b954890fc317f52689a20d97 100644 (file)
@@ -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>
 #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 @@ asmlinkage int do_sigsuspend(struct pt_regs *regs)
 
 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 @@ asmlinkage int do_sigreturn(unsigned long __unused)
 
        /* 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 @@ asmlinkage int do_sigreturn(unsigned long __unused)
        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 @@ asmlinkage int do_sigreturn(unsigned long __unused)
            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 @@ asmlinkage int do_sigreturn(unsigned long __unused)
          }
        __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 @@ asmlinkage int do_sigreturn(unsigned long __unused)
                /* NOTREACHED */
        }
 
-       return regs->ptregs.d0;
+       return regs->d0;
 badframe:
         do_exit(SIGSEGV);
 }
@@ -275,25 +257,31 @@ badframe:
 
 #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 @@ static void setup_frame (struct sigaction * sa, unsigned long **fp,
            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 @@ static void setup_frame (struct sigaction * sa, unsigned long **fp,
 
 /* 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 @@ static void setup_frame (struct sigaction * sa, unsigned long **fp,
  * 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 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
                        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 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
                                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;
-       }
-       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;
+               handle_signal(signr, sa, oldmask, regs);
+               return 1;
        }
-       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;
 }
index 9d330c2237add81c42c07b78fe1a19fbe97d5676..9f79a09b315508de2ded9861c03b84f1d4246fa0 100644 (file)
@@ -6,7 +6,6 @@
  * platform.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #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 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
                        : "=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 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
 
     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 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
            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 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
                        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 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
 
     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 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
            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 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
                        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 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
     {
       /* 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 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
         : "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);
 }
index b14d08d5af1ef3a9172217788aea95a40422ab2a..45c52e7f594c253df8795d9628cd81a55a21118a 100644 (file)
@@ -32,7 +32,7 @@ static inline int set_rtc_mmss(unsigned long nowtime)
  * 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;
index 134e804c6727da5aa3d6a163309f0ebdbb7955d1..cfaff152f960425e02ce774d193adfd727fc32ec 100644 (file)
 #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 @@ void trap_init (void)
                 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 @@ void trap_init (void)
                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 @@ char *space_names[] = {
 
 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 @@ static inline void access_error060 (struct frame *fp)
                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 @@ static inline void access_error060 (struct frame *fp)
                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 @@ static unsigned long probe040 (int iswrite, int fc, unsigned long addr)
 
        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 @@ static unsigned long probe040 (int iswrite, int fc, unsigned long addr)
                              : "g" (addr)
                              : "a0");
 
-
        set_fs (fs);
 
        return mmusr;
@@ -351,14 +348,19 @@ static inline void access_error040 (struct frame *fp)
                                 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 @@ static inline void bus_error030 (struct frame *fp)
          {
            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 @@ static inline void bus_error030 (struct frame *fp)
 #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 @@ static inline void bus_error030 (struct frame *fp)
                    force_sig(SIGSEGV, current);
                    return;
            } else {
-#ifdef DEBUG
+#if 0
                    static volatile long tlong;
 #endif
 
@@ -484,12 +486,13 @@ static inline void bus_error030 (struct frame *fp)
 
            /* 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 @@ static inline void bus_error030 (struct frame *fp)
                      }
                  }
              }
+#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 @@ static inline void bus_error030 (struct frame *fp)
                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 @@ static inline void bus_error030 (struct frame *fp)
                force_sig(SIGSEGV, current);
                return;
        } else {
+#if 0 /* stale ATC entry??  Ignore it */
+
 #ifdef DEBUG
                static volatile long tlong;
 #endif
@@ -605,18 +611,22 @@ static inline void bus_error030 (struct frame *fp)
                }
 
 #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 @@ asmlinkage void buserr_c(struct frame *fp)
 #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 @@ static void dump_stack(struct frame *fp)
            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 @@ void bad_super_trap (struct frame *fp)
                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 @@ asmlinkage void trap_c(struct frame *fp)
                break;
        }
 
-       force_sig (sig, current);
+       send_sig (sig, current, 1);
 }
 
 asmlinkage void set_esp0 (unsigned long ssp)
index 611e99c23c294d115832e289dea23adb76efaed8..f152e28e47144f62560ba4c766b4b2a8b5e83b4f 100644 (file)
@@ -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
index e0ab3433d783a57c8b7ae9b51b57b2d2e889d5af..73e181823d9b4ec371b1fa4bb775f3776b107dd3 100644 (file)
@@ -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 @@ void * memcpy(void * to, const void * from, size_t n)
     {
       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 --git a/arch/m68k/lib/memset.c b/arch/m68k/lib/memset.c
new file mode 100644 (file)
index 0000000..d55fdb2
--- /dev/null
@@ -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 --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S
new file mode 100644 (file)
index 0000000..82dc388
--- /dev/null
@@ -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
index 87e548937a1854ee7bbf8251d9e1b843f4c252d4..f39179f7d51e76d4b4ed83c235b7795284003831 100644 (file)
@@ -29,14 +29,17 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
                              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 @@ good_area:
            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 @@ good_area:
  * 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 @@ bad_area:
 
        return 1;
 }
+
index 6bd45439b35f5ed3689d2ee750c8a862c2c88b51..c08fddc0888ac882207c09837f5916de03d404de 100644 (file)
 #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 @@ void show_mem(void)
 #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 @@ static unsigned long map_chunk (unsigned long addr,
 #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 @@ static unsigned long map_chunk (unsigned long addr,
         * 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 @@ static unsigned long map_chunk (unsigned long addr,
                        pindex = 0;
                }
 
-               if (is040) {
+               if (CPU_IS_040_OR_060) {
                        int i;
                        unsigned long ktable;
 
@@ -306,30 +298,14 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 #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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                }
                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);
        }
index 3b7e9711c657f1ba6bab49c51e075868ac80a899..05aa8499dbc1e25131e4586320ea93d38b889259 100644 (file)
 #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 @@ unsigned long mm_vtop (unsigned long vaddr)
        /* 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 @@ unsigned long mm_vtop (unsigned long vaddr)
 
          return paddr;
 
-       } else if (m68k_is040or060 == 4) {
+       } else if (CPU_IS_040) {
          unsigned long mmusr;
          unsigned long fs = get_fs();
 
@@ -414,17 +414,18 @@ unsigned long mm_ptov (unsigned long paddr)
 
 /* 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 @@ unsigned long mm_ptov (unsigned long paddr)
 
 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 @@ void cache_clear (unsigned long paddr, int len)
            }
        }
     }
-#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_clear (unsigned long paddr, int len)
 
 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 @@ void cache_push (unsigned long paddr, int len)
            }
        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 (unsigned long paddr, int len)
 
 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 @@ void cache_push_v (unsigned long vaddr, int len)
            }
        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 @@ unsigned long kernel_map(unsigned long paddr, unsigned long size,
         * 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 @@ unsigned long kernel_map(unsigned long paddr, unsigned long size,
        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 @@ unsigned long kernel_map(unsigned long paddr, unsigned long size,
                        pindex = 0;
                }
 
-               if (m68k_is040or060) {
+               if (CPU_IS_040_OR_060) {
                        int i;
                        unsigned long ktable;
 
@@ -838,7 +834,7 @@ void kernel_set_cachemode( unsigned long address, unsigned long size,
        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 --git a/arch/m68k/tools/amiga/Makefile b/arch/m68k/tools/amiga/Makefile
new file mode 100644 (file)
index 0000000..b72ccb0
--- /dev/null
@@ -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
+
index f352a2aa3dc99c15e6f3aeff21f29199bd2c4a47..9affff5659ccaf214690164a91a236e619e06b81 100644 (file)
@@ -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
index dfa48f764b807ce320bfe770968f4bcc61cb9edd..4a244f704549fd7a2f101374c4ec872307bf9941 100644 (file)
@@ -1043,7 +1043,7 @@ static void setup_DMA(void)
        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 @@ static void setup_format_params(int track)
 
        /* 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 @@ static void config_types(void)
                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 @@ static int floppy_read(struct inode * inode, struct file * filp,
        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;
index d557b2f9c7634986e8f4652e7e05cbffd0edf44a..4fafda17c8ff9552d1ecfa8f0f87e04fbd932288 100644 (file)
@@ -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>
  *
  * 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 @@ void idetape_setup (ide_drive_t *drive)
 {
        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 @@ void idetape_setup (ide_drive_t *drive)
         *      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 @@ void idetape_setup (ide_drive_t *drive)
        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;
 }
 
index 7786d270a841b01b856b7a407412868769e11777..971c63ec4ef23c8ce763171479b4c26594c2601f 100644 (file)
@@ -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>
  */
 
 #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.
  */
index 4e247cd4e08bf629bc768a4e43aa494fe51e8a0f..441d22059ba2c6ab2bd8593effc1814945fc7882 100644 (file)
@@ -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)
  */
  * 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 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
                } 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 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
                } 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 @@ static void atapi_reset_pollfunc (ide_drive_t *drive)
                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 @@ static int ide_open(struct inode * inode, struct file * filp)
        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 @@ static int revalidate_disk(kdev_t i_rdev)
        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 @@ void ide_setup (char *s)
         */
        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;
@@ -2895,6 +2919,9 @@ void ide_setup (char *s)
                        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;
                                drive->cyl      = drive->bios_cyl  = vals[0];
index 772f2c6d7d0992f3d32e1a8d8720ab4549f71492..98ec3d939870d5ccff4da9394b1d8c905e010db6 100644 (file)
@@ -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 @@ typedef struct ide_drive_s {
        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 */
index 1a6d5961725382a5e955412b69684b8226464db1..bbbeec8c7cb3e0c7ed309010eca33674dc32556c 100644 (file)
  */
 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
index e14f9d258740de3d017b3299335580d48f50481d..c57dc2cdf2552b9fd62b4d563413bf4888a35563 100644 (file)
@@ -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 @@ static XD_SIGNATURE xd_sigs[] = {
        { 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 @@ int xd_init (void)
 }
 
 /* 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 @@ static u_char xd_detect (u_char *controller,u_char **address)
 /* 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 @@ static u_char xd_initdrives (void (*init_drive)(u_char drive))
        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 @@ static void xd_dtc_init_drive (u_char drive)
                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 @@ static void xd_wd_init_drive (u_char drive)
                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 @@ static void xd_seagate_init_drive (u_char drive)
 }
 
 /* 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 --git a/drivers/block/xd.h b/drivers/block/xd.h
new file mode 100644 (file)
index 0000000..02ee8ee
--- /dev/null
@@ -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 */
index 18c1bed2a84c32f2f50a18eadc310162353d54ab..47250be9153b0bc996e57e5578e989fa8579fe64 100644 (file)
 #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>
index b255a78fcfd00040049725f07dbf035e338e976d..807f1d57ad527dbbf47c04101f14bd4178b280d0 100644 (file)
@@ -305,7 +305,7 @@ static void do_apm_timer(unsigned long);
 
 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 @@ static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
        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;
index 67ed7dd4a238c0fb6a852b7f58b30ac0b2510ce4..6501808d682509bdca4128de116c1651e7c0cab6 100644 (file)
@@ -134,12 +134,14 @@ static int open_mouse(struct inode * inode, struct file * file)
 }
 
 
-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;
 
index 75663af5642de951e127beaea6f632edfb58effb..7be14631274fdd64a9036ddc26b20a07af7e0511 100644 (file)
@@ -155,7 +155,8 @@ static int open_mouse(struct inode * inode, struct file * file)
  * 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 @@ static int write_mouse(struct inode * inode, struct file * file, const char * bu
  * 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;
index dbeadbddd8d8878c736237145991eeafa6d9d128..4d1358d942531093c3409c047ca63a0ed912f834 100644 (file)
@@ -30,7 +30,7 @@ static char rcsid[] =
  * 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_detect_pci()
                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 *)
index 4ec106d598c4ed6a0bff347fb065f6399c873b12..4e71d0b2e1c9fc612ef277de1818bb3b62fe7aad 100644 (file)
@@ -61,10 +61,10 @@ static int ftape_open(struct inode *ino, struct file *filep);
 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 @@ static int ftape_ioctl(struct inode *ino, struct file *filep,
 
 /*      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 @@ static int ftape_read(struct inode *ino, struct file *fp, char *buff, int req_le
 
 /*      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;
index 2cc26a90f5765d599913c6c4fad11be4ec4eb3df..b884ad2bdfd6a79809a391313b3a2c3bb5f32733 100644 (file)
@@ -538,8 +538,8 @@ static int  stli_eisamemprobe(stlibrd_t *brdp);
 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 @@ void cleanup_module()
                }
 
                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 @@ static int stli_initecp(stlibrd_t *brdp)
        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 @@ static int stli_initonb(stlibrd_t *brdp)
        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 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                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 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                                foundit = 1;
                }
                if (brdp->memaddr >= 0x100000)
-                       vfree(brdp->membase);
+                       iounmap(brdp->membase);
                if (foundit)
                        break;
        }
@@ -4045,7 +4045,8 @@ static int stli_initbrds()
  *     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 @@ static int stli_memread(struct inode *ip, struct file *fp, char *buf, int count)
        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 @@ static int stli_memread(struct inode *ip, struct file *fp, char *buf, int count)
  *     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 @@ static int stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int
        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);
index e546dda61b49d22e03e349c515f447cb899a3c23..5c1332567e0ee4656b0eba92c0f227af4628956d 100644 (file)
@@ -295,7 +295,8 @@ static inline int lp_write_polled(unsigned int minor, const char * buf, int coun
        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 @@ static int lp_write(struct inode * inode, struct file * file, const char * buf,
                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;
 }
index 94732f1a2cab1399c2a03912fdb750a6ed4e365c..39fa103e20bd7bb09776e3f058232bbd721912ae 100644 (file)
@@ -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 isdn_init(void);
 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 @@ static int read_mem(struct inode * inode, struct file * file, char * buf, int co
                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 @@ static int write_mem(struct inode * inode, struct file * file, const char * buf,
                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 write_mem(struct inode * inode, struct file * file, const char * buf,
 
 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 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
         * 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 @@ static int read_kmem(struct inode *inode, struct file *file, char *buf, int coun
        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 @@ static int read_port(struct inode * inode, struct file * file,char * buf, int co
        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 @@ static int write_port(struct inode * inode, struct file * file, const char * buf
        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 @@ static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_st
        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 @@ static int write_full(struct inode * inode, struct file * file, const char * buf
  * 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 @@ static int null_lseek(struct inode * inode, struct file * file, off_t offset, in
  * 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:
index d113b43f42156a9b8dba22dd37b9e551b99c7357..524e0420e286f3de056f9b6b5f2d7164dd755822 100644 (file)
@@ -127,12 +127,14 @@ static int open_mouse(struct inode * inode, struct file * file)
 }
 
 
-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;
 
index d9b52af4f3b91b4528c6f1cdddd49a789b620e81..63916254980fb45ca00b15af62561e9db5ffa0f1 100644 (file)
@@ -388,11 +388,12 @@ static int open_qp(struct inode * inode, struct file * file)
  * 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 @@ static int write_aux(struct inode * inode, struct file * file, const char * buff
  * 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 @@ static int write_qp(struct inode * inode, struct file * file, const char * buffe
  * 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;
index 989d949e9f84e125f30a3871fab7b571f860e314..53968b33c54464536c0ec44d9c66a4b5e00b7349 100644 (file)
@@ -181,66 +181,41 @@ static void pty_flush_buffer(struct tty_struct *tty)
 
 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;
 }
 
index df829a893c5710bb9e75368d8246d78b928949ea..e3bba29540a9ae08a70dfb113fa52ba4ff9e235d 100644 (file)
@@ -328,14 +328,14 @@ static struct timer_rand_state *irq_timer_state[NR_IRQS];
 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 @@ void get_random_bytes(void *buf, int nbytes)
        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 @@ random_read(struct inode * inode, struct file * file, char * buf, int nbytes)
        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 @@ random_select(struct inode *inode, struct file *file,
        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 @@ random_ioctl(struct inode * inode, struct file * file,
                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;
index 7310f63083bd0015aced8fd2def5df49ae594d6b..95c1f21ec384ad58a0c454c8fe61c74944d39e8b 100644 (file)
@@ -108,8 +108,6 @@ static inline unsigned short scr_readw(unsigned short * addr)
  *
  */ 
 
-#ifdef __alpha__
-
 #include <asm/io.h> 
 
 /*
@@ -147,33 +145,6 @@ static inline unsigned short scr_readw(unsigned short * addr)
        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)
index 92e0cfc18695c4e7c524f9c4d6314150e7804f68..ddc22562e7060870594a26b124c499865e9af952 100644 (file)
@@ -1878,7 +1878,8 @@ static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 } /* 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 @@ static int qic02_tape_lseek(struct inode * inode, struct file * file, off_t offs
  * 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 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf,
 
        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 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf,
        /* 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 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf,
  * 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 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, const char
 
        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 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, const char
        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 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, const char
        }
        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 */
 
index 68749257e282f5e5d2f1f1c736f28b677874e9da..7b6bad9203fea3923cf75b4b2ca844b7201eca9c 100644 (file)
@@ -110,8 +110,8 @@ char vt_dont_switch = 0;
 
 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 @@ int tty_check_change(struct tty_struct * tty)
        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 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
        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 @@ void start_tty(struct tty_struct *tty)
        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 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
                }
 #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 @@ static inline int do_tty_write(
        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 inline int do_tty_write(
 }
 
 
-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;
index df9af352a75691f819ae8043aa0d4a8d743fc354..116682d3805a5276cb98fc57819e1258819c8709 100644 (file)
@@ -36,8 +36,8 @@ vcs_size(struct inode *inode)
        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 @@ vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
        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 @@ vcs_read(struct inode *inode, struct file *file, char *buf, int count)
                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 @@ vcs_read(struct inode *inode, struct file *file, char *buf, int count)
        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 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, int count)
                return -ENXIO;
 
        size = vcs_size(inode);
-       if (count < 0 || p > size)
+       if (p > size)
                return -EINVAL;
        if (count > size - p)
                count = size - p;
index 6baeab77f5aa8da211d297f4168e3dc92c6e4317..0087c9c7cd0c2bee462c0ce573d3f039faab8076 100644 (file)
@@ -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 */
index a2d93ea55e128dff3ac17e91929eb43c519f4207..e9834afa6bcf4cc8f1b98af63a3c7db00884fe61 100644 (file)
@@ -225,10 +225,10 @@ check_board_dma(struct device *dev)
        /*
         *      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 @@ dgrs_download(struct device *dev)
        /*
         * 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 @@ dgrs_download(struct device *dev)
        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 @@ cleanup_module(void)
                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);
 
index a2d93ea55e128dff3ac17e91929eb43c519f4207..e9834afa6bcf4cc8f1b98af63a3c7db00884fe61 100644 (file)
@@ -225,10 +225,10 @@ check_board_dma(struct device *dev)
        /*
         *      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 @@ dgrs_download(struct device *dev)
        /*
         * 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 @@ dgrs_download(struct device *dev)
        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 @@ cleanup_module(void)
                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);
 
index 60661b6dbb4ba08dc971f9486b60fc16a1ecc1c4..2a6329b75f5a78d18b3ffcf5806425cb4e6e0290 100644 (file)
@@ -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 @@ static char version[] =
 #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 @@ static char version[] =
 #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 "eexpress.h"
 
-#include "eth82586.h"
-
-#define PRIV(x)         ((struct net_local *)(x)->priv)
 #define EEXP_IO_EXTENT  16
 
 /*
@@ -145,14 +104,15 @@ static unsigned int net_debug = NET_DEBUG;
 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 @@ struct net_local
        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 @@ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
  * 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 @@ int express_probe(struct device *dev)
        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 @@ static int eexp_open(struct device *dev)
                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 @@ static int eexp_open(struct device *dev)
 }
 
 /*
- * 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 @@ static struct enet_statistics *eexp_stats(struct device *dev)
 {
        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 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
                        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 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
        }
        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 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
        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 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
 /*
  * 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 @@ static void eexp_hw_rx(struct device *dev)
                                }
                                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 @@ static void eexp_hw_tx(struct device *dev, unsigned short *buf, unsigned short l
                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 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 
        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++)
        {
-               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);
-
-               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;
-               }
+               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;
+       }
 
-               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);
+       /* 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 (net_debug) 
-               printk(version);
+
+       lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
+
        dev->open = eexp_open;
        dev->stop = eexp_close;
        dev->hard_start_xmit = eexp_xmit;
@@ -796,16 +860,18 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 }
 
 /*
- *     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 @@ static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char lo
        }       
        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_readeeprom(unsigned short ioaddr, unsigned char lo
 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 @@ static unsigned short eexp_hw_lasttxstat(struct device *dev)
        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 @@ static void eexp_hw_txrestart(struct device *dev)
        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 @@ static void eexp_hw_txrestart(struct device *dev)
 }
 
 /*
- * 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 @@ static void eexp_hw_txinit(struct device *dev)
        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));
-                       }
-               }
-       }
 
-       outw_p(lp->rx_buf_end,ioaddr+WRITE_PTR);
-       start_code[28] = (dev->flags & IFF_PROMISC)?(start_code[28] | 1):(start_code[28] & ~1);
+       set_loopback(dev);  
+
+       /* 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 @@ static void eexp_hw_init586(struct device *dev)
                }
        }
 
-       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 @@ static void eexp_hw_init586(struct device *dev)
                }
        }
   
-       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 @@ static void eexp_hw_init586(struct device *dev)
        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 @@ static struct device dev_eexp[EEXP_MAX_CARDS] =
          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 @@ void cleanup_module(void)
  * 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 --git a/drivers/net/eexpress.h b/drivers/net/eexpress.h
new file mode 100644 (file)
index 0000000..ff42bdd
--- /dev/null
@@ -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
index 5c6e38d48f7b1df9b52303fd4a2e908bb14d0a83..5caef729b12d4e3001257596880fd3ac72d07517 100644 (file)
@@ -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 @@ static int eql_enslave(struct device *dev, slaving_request_t *srqp)
 
        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 --git a/drivers/net/eth82586.h b/drivers/net/eth82586.h
deleted file mode 100644 (file)
index c2178ff..0000000
+++ /dev/null
@@ -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)
index 01717b62878f7ca7cbeb90037b413e1006d5eb9f..21997a8338ca20219b942a6f9317fa4e0d4610a7 100644 (file)
@@ -390,9 +390,9 @@ static int hp100_probe1( struct device *dev, int ioaddr, int bus )
         }
       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 @@ void cleanup_module( void )
   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;
 }
index 8925ee5286eaff2d3939baffe4b665d802e2c9bc..f43581e26159664f00ef4001332a4f596060576b 100644 (file)
@@ -452,7 +452,7 @@ static Scsi_Host_Template *the_template = NULL;
  *     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.  
  */
 
 /* 
index 5e904a521fe8f9f24b6298319bdf8031756e8ff1..70f1a3de6d08684373b0f7f4235ced55aeaff8bb 100644 (file)
@@ -156,6 +156,11 @@ static volatile int main_running = 0;
 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 AM53C974_detect(Scsi_Host_Template *tpnt)
 {
 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 @@ struct AM53C974_hostdata *hostdata;
 
 #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 (!search) {
    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(CNTLREG1, CNTLREG1_DISR | instance->this_id);
 AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
 udelay(10);
 AM53C974_config_after_reset(instance);
-
-return(0);
+return(1);
 }
 
 /*********************************************************************
@@ -1797,7 +1803,11 @@ if (cfifo) {
    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(STCLREG, (unsigned char)(length & 0xff));
 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->result = DID_RESET << 16;
 cmd->scsi_done(cmd);
 return SCSI_ABORT_SUCCESS;
 }
+
+#ifdef MODULE
+static Scsi_Host_Template driver_template = AM53C974;
+
+#include "scsi_module.c"
+#endif
index 8481e5e06468ec780a4c22fbc71417ffa81b2611..ec170552073ea12b8c42bc7086847fc01ef5be9c 100644 (file)
 #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 @@ struct AM53C974_hostdata {
     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 *)                 */  \
index ff52bb0fa34c554d1207d5d206ba02853ad293c3..b5b341b989b7c4ab1cc153136cf7a5b6aba39a75 100644 (file)
@@ -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 --git a/drivers/scsi/README.in2000 b/drivers/scsi/README.in2000
new file mode 100644 (file)
index 0000000..dacd326
--- /dev/null
@@ -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
+
index bd377431d4858191520f170caaaec32d3ef554a3..c7f037b8d36211e8abce7dbe979325ce8c10e174 100644 (file)
@@ -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 */
 
 /*
 
 
   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)
         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)
         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.
         '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.
         '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'.
  
            --- 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
      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.
 
         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
      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
             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.
             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
      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
  */
 
 #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 @@ typedef unsigned char uchar;
 #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 @@ typedef unsigned char uchar;
 #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 @@ typedef unsigned char uchar;
 #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 @@ typedef unsigned char uchar;
 #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 @@ typedef unsigned char uchar;
 #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 @@ typedef struct asc_risc_sg_list_q {
 #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 @@ typedef struct asc_risc_sg_list_q {
 #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 @@ typedef struct asc_dvc_var {
        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 @@ typedef struct asc_cap_info_array {
 #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 @@ typedef struct asceep_config {
 #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 @@ int                 AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SA
 #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 @@ typedef Scsi_Cmnd                        REQ, *REQP;
 #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 @@ struct asc_stats {
        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 @@ struct asc_stats {
        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 @@ struct asc_stats {
  * 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 @@ typedef struct asc_queue {
  * 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 @@ struct proc_dir_entry proc_scsi_advansys =
 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 @@ STATIC void               advansys_select_queue_depths(struct Scsi_Host *,
                                                                                                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 uchar            asc_get_cfg_byte(PCI_DATA *);
 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 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
                                   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 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
        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 @@ advansys_detect(Scsi_Host_Template *tpnt)
        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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                         * 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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        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 @@ advansys_detect(Scsi_Host_Template *tpnt)
 #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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                                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_detect(Scsi_Host_Template *tpnt)
                                                        "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 @@ advansys_detect(Scsi_Host_Template *tpnt)
                        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 @@ advansys_detect(Scsi_Host_Template *tpnt)
 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 @@ advansys_release(struct Scsi_Host *shp)
 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 @@ advansys_info(struct Scsi_Host *shp)
                } 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 @@ advansys_command(Scsi_Cmnd *scp)
 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 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 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 @@ advansys_abort(Scsi_Cmnd *scp)
                                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)
 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.
@@ -3616,86 +3868,193 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
                        (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
 #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 @@ Scsi_Host_Template driver_template = ADVANSYS;
  * 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, struct pt_regs *regs)
 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 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
         */
        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 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 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) {
@@ -3917,6 +4303,27 @@ advansys_command_done(Scsi_Cmnd *scp)
        scp->SCp.Status = 1;
 }
 
+/*
+ * 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'.
  *
@@ -3952,20 +4359,21 @@ advansys_command_done(Scsi_Cmnd *scp)
  *  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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
        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_execute_scsi_cmnd(Scsi_Cmnd *scp)
                 */
                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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                 * 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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
                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 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 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_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
        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 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
                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 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 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_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 
        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_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 
        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_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
                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_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
        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 @@ asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
 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,29 +5211,102 @@ asc_dequeue(asc_queue_t *ascq, int tid)
 {
        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
@@ -4837,34 +5320,61 @@ asc_dequeue(asc_queue_t *ascq, int tid)
 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 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 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 @@ asc_execute_queue(asc_queue_t *ascq)
        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 @@ asc_execute_queue(asc_queue_t *ascq)
 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 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 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;
@@ -5068,6 +5583,70 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
        return totlen;
 }
 
+/*
+ * 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()
  *
@@ -5082,7 +5661,7 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 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_board_info(struct Scsi_Host *shp, char *cp, int cplen)
        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 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
                 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 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
        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 @@ DvcWritePCIConfigByte(
 }
 
 /*
- * 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 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        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_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        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_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
        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 @@ AscIsrChipHalted(
                                        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 @@ AscIsrChipHalted(
                        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 @@ AscIsrChipHalted(
                                }
 #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 @@ AscScsiSetupCmdQ(
        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 @@ AscExeScsiQueue(
                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 @@ AscExeScsiQueue(
                        ((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 @@ AscExeScsiQueue(
                                        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 @@ AscExeScsiQueue(
                                  ) {
                                        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 @@ AscGetNumOfFreeQueue(
                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 @@ AscPutReadyQueue(
                ((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 @@ AscInitAscDvcVar(
        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 @@ AscInitAscDvcVar(
                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 @@ AscInitFromEEP(
        }
        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 @@ AscInitWithoutEEP(
        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 @@ AscInitWithoutEEP(
                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 @@ AscInitPollIsrCallBack(
        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 @@ AscInitPollIsrCallBack(
                        (*asc_isr_callback) (asc_dvc, scsi_done_q);
                }
        }
+       ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
        return;
 }
 
@@ -9316,6 +9914,7 @@ AscInitPollTarget(
                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 @@ AscInitPollTarget(
                                        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 @@ AscInitPollTarget(
                                }
                        }
                        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 @@ AscInitPollTarget(
                                        }
                                }
                        }
-#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 @@ PollQueueDone(
 )
 {
        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 @@ PollQueueDone(
                                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 @@ PollScsiInquiry(
        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 @@ PollScsiStartUnit(
        }
        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 @@ PollScsiReadCapacity(
        }
        return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
-#endif
 
 ulong dosfar       *
 swapfarbuf4(
@@ -9542,7 +10130,6 @@ swapfarbuf4(
        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 @@ InitTestUnitReady(
        }
        return (0);
 }
-#endif
 
 int
 AscPollQDone(
@@ -9866,7 +10452,6 @@ AscScsiInquiry(
        return (0);
 }
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 AscScsiReadCapacity(
                                           REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9890,9 +10475,7 @@ AscScsiReadCapacity(
        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 @@ AscScsiTestUnitReady(
        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 @@ AscScsiStartStopUnit(
        scsiq->r2.cdb_len = 6;
        return (0);
 }
-#endif
index 29fea2c522e1251009c03cb74906370ac7168ff1..4683ea293adc36d8b5a1cf4d249f46fff2033704 100644 (file)
@@ -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 @@ void advansys_setup(char *, int *);
        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 @@ void advansys_setup(char *, int *);
        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 */
index fec158fff055a703f5864ec9168cba6ce3160269..78c089fd7b28abfa5ff54afd4236ad746d33f2d8 100644 (file)
@@ -523,19 +523,19 @@ static unsigned short ports[] =
 
 #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 @@ static void *addresses[] =
    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 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
     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;
index 6daa16e76c84f277ad1039b634f5d728dbf585b1..52ec1d4a50bdd2043bb2f3577122f232b81fa0bb 100644 (file)
 
 #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 @@ static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
        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 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     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 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
          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 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
       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 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
       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 @@ static void setup_mailboxes(int bse, struct Scsi_Host * shpnt)
 
     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 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
 
                    /* 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;
                    }
index 7fe6c3af6bebefd5a5c0330972d3259d04678957..81bfb521c0d0728bfb38ea1cd9283276b5118c48 100644 (file)
 #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 @@ struct proc_dir_entry proc_scsi_in2000 = {
    };
 
 
+/* 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 @@ char buf[32];
          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 @@ char buf[32];
 
 /* 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,33 +2193,23 @@ int size;
       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)
 {
 
index 60bdd3cb9a638ce8f3dcd5db9e7045099ca4c626..e2f17f89667ef0a6bb5ecc74250b64220dcc186b 100644 (file)
@@ -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 --git a/drivers/scsi/in2000.readme b/drivers/scsi/in2000.readme
deleted file mode 100644 (file)
index 1aefc0a..0000000
+++ /dev/null
@@ -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
-
index a125f089a2c3d8fd3c87de05d4049618165a3a33..da9427e912c15baf6d63997eec1c24c97651db02 100644 (file)
@@ -301,7 +301,7 @@ typedef     int             vm_size_t;
 **
 **     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 @@ static inline vm_offset_t remap_pci_mem(u_long base, u_long size)
 {
        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 @@ static void ncr53c8xx_timeout(unsigned long np);
 #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 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
 #   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
@@ -4789,6 +4789,11 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        */
        ncr_wakeup (np, code);
 
+       /*
+       **      Remove Reset, abort ...
+       */
+       OUTB (nc_istat,  0      );
+
        /*
        **      Init chip.
        */
@@ -4838,8 +4843,6 @@ void ncr_init (ncb_p np, char * msg, u_long code)
        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 @@ printk("ncr53c8xx : interrupt received\n");
 #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);
index fc70b86888dadcb179c6a3c0d076ea358d2b18c7..401ced5a72c8aed7c2fd07a5d80d820d9d626ba3 100644 (file)
@@ -652,6 +652,8 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
     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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
                  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 @@ static void resize_dma_pool(void)
        
     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;
index 7510446f532f0c098ad442dd5458f092909fab9c..30d5ba79d1dc7ca43fe93ed3160c2347ef976d9b 100644 (file)
@@ -132,6 +132,7 @@ extern const unsigned char scsi_command_size[8];
 #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
index 4c561845a64fb1e481262f28c6b49e1066102fa2..cb08eef6edfd20c87a9bb2c1ac2164f0d1e8be3d 100644 (file)
@@ -545,8 +545,9 @@ void sr_photocd(struct inode *inode)
 
     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 @@ void sr_photocd(struct inode *inode)
        
        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;
        }
index ffd39202a3bc73eeee218b7746118a26f881c714..1b71792c78df2c65d63fd51c3e10b966470b8d65 100644 (file)
@@ -322,7 +322,7 @@ static int board_inquiry(unsigned int j) {
    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 @@ static int board_inquiry(unsigned int j) {
    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 @@ static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
    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 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    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 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       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 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       }
 
    /* 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 @@ static void u14_34f_interrupt_handler(int irq, void *dev_id, struct pt_regs * re
         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);
index af7378c27294f2059b4aa9ae27565c3dfac2469e..2a64fd8d2b24fbd6f1ae58c8a529b3cf14f6d2ab 100644 (file)
@@ -735,11 +735,13 @@ ask_parameters (void)
    * 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",
index 0191620b283931bbfbd6581d5faa36e72ff31971..3a835eeee2e50cb04ac8a643ea1ddcdd0ca9d575 100644 (file)
@@ -546,8 +546,10 @@ sound_install_audiodrv (int vers,
   audio_devs[num_audiodevs] = op;
   num = num_audiodevs++;
 
+#ifdef CONFIG_AUDIO
   DMAbuf_init ();
   audio_init ();
+#endif
   return num;
 }
 
index 4f4ea3651f3166beeb6902eba6c2eb7d5fb18698..448bc5e9b52f7b694d9f9ff669d07037b8a39cb9 100644 (file)
@@ -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>
index 15068a41fcdda153912c6c6259c6c02981661d11..850c0bfcf0d2bae3a8052c65105b3a3e8386a65f 100644 (file)
@@ -289,7 +289,7 @@ sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma)
              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;
index 360d27eefb8aa79f91cd85cf292f5beee30c6f53..c90db28ad5389f9db255b34191eebbc87b8ebedf 100644 (file)
@@ -60,8 +60,8 @@ static void set_brk(unsigned long start, unsigned long end)
 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 @@ aout_core_dump(long signr, struct pt_regs * regs)
  */
 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 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
        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 @@ do_load_aout_library(int fd)
                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;
index 1252182da2c9adcd38f0055e83b1bd3893e6c4d3..e2a504945b962304ad5043a4c8fc37f3968b0dbb 100644 (file)
@@ -108,7 +108,8 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
                                  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 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
        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 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
                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 @@ do_load_elf_library(int fd){
                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_write(struct file *file, const void *addr, int nr)
 
 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;
index 0ac60bcf719156615d885020ce4b781255c5ace2..6a65b031185672cb68223b3aea0bc67a23c46b8e 100644 (file)
@@ -20,7 +20,8 @@ extern int *blksize_size[];
 #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 @@ int block_write(struct inode * inode, struct file * filp, const char * buf, int
        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;
index 771b4abc2ec7dd8d2eb30252bc8726a3d05f3d21..d482b0ebd6757d9b4734aea1a7fcb7c6f5d68443 100644 (file)
@@ -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 @@ void buffer_init(void)
 {
        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;
index 4dd1683ea3893878c331afd6d71cfa9867fb4035..2645e8e935e2eaa3909076dd7964a0bdeacf2761 100644 (file)
@@ -222,8 +222,8 @@ static void write_dquot(struct dquot *dquot)
                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 @@ static void read_dquot(struct dquot *dquot)
                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);
index fe9b3fdb4d338bbf4129fa67c8b0805f6412370a..3466b4d272797724cfa93f84f077b5bca7ef66c8 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -338,8 +338,8 @@ int read_exec(struct inode *inode, unsigned long offset,
                        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;
index 58afb98b2d8c3815109305623bd40b04c619422e..945dfb2136635171f0086e8912454435b59b8990 100644 (file)
@@ -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;
 }
index a00d0f41fa96fd6a274757f03c57a6343b6c26bf..acd3eae4ce8b8c376dd2e80a810e27011eb5ee7e 100644 (file)
@@ -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 @@ struct inode_operations ext_file_inode_operations = {
        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 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
        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;
index e042edbfe1b8c76f34fbc8a9fd13dde20981acc3..9153984f0b22a2b0626ac25c7835633563b7b54a 100644 (file)
@@ -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;
 }
index 05c7c427463895f4cbe4fdd8f2eb04356a93532f..12081b07ef602c6c03b448edfddf05be3b2f2d57 100644 (file)
@@ -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 @@ struct inode_operations ext2_file_inode_operations = {
        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 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
                                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);
index db537c6660a398f1a6ae2710ab6235b02760a6c0..f8c9a28e8cb9bed32b54c9f2835ae34d3fe9294f 100644 (file)
@@ -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;
 }
index f2b2ec2308d9fbb52151fd87b4a54ad53c72b2ab..3c8ca916c5408691bccbe820af0eb59f76858706 100644 (file)
@@ -152,11 +152,11 @@ static void fat_prefetch (
 /*
        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 @@ int fat_file_read(
                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 @@ int fat_file_read(
 /*
        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 @@ int fat_file_write(
  */
        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) {
index 1b772fdea80454de10d1d4716aab6fa1cecac141..120c522e7f82b13b135833e6d93b06a40f4e249b 100644 (file)
@@ -244,6 +244,9 @@ int date_dos2unix(unsigned short time,unsigned short date)
            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;
 }
 
index 0566658e670adaec539c0169712842047edf6309..f3a9eb54b071504e23e50366aa8b1dcfdc0e48bf 100644 (file)
@@ -144,7 +144,7 @@ static const struct super_operations hpfs_sops =
 
 /* 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 @@ static const struct inode_operations hpfs_file_iops =
 
 /* 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 int ino_is_dir(ino_t ino)
 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);
 }
 \f
 /* super block ops */
@@ -878,8 +878,8 @@ static unsigned count_one_bitmap(kdev_t dev, secno secno)
  * 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 @@ static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
        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;
 }
index 03a190bbc309241be48246f6fead3c551a37683d..09b7920bdb446c7936298c1f953a370e7b489b3d 100644 (file)
  *  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.
  *  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 void flock_remove_locks(struct file_lock **before, struct file *filp);
 
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
-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;
+       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;
 }
 
-/* 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.
+/* 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 *bfl, 
-                                     struct file_lock *fl)
+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 @@ asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
        
        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 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
        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 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
        /* 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 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
         * 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_locked(struct inode *inode)
 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 @@ int locks_mandatory_locked(struct inode *inode)
 
        /* 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 @@ int locks_mandatory_area(int read_write, struct inode *inode,
 {
 #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 @@ repeat:
                                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 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
 {
        off_t start;
 
-       fl->fl_flags = F_POSIX;
+       fl->fl_flags = FL_POSIX;
 
        switch (l->l_type) {
        case F_RDLCK :
@@ -495,11 +554,11 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
                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 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
        fl->fl_file = filp;
        fl->fl_owner = current;
        fl->fl_wait = NULL;             /* just for cleanliness */
-       
+
        return (1);
 }
 
@@ -555,7 +614,7 @@ static int flock_make_lock(struct file *filp, struct file_lock *fl,
                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 locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
 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 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
 
        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 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
        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 @@ repeat:
                        }
                        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 @@ repeat:
                                 * 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 @@ static int posix_lock_file(struct file *filp, struct file_lock *caller,
        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 @@ repeat:
                                        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 @@ repeat:
                                 * 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 @@ repeat:
                        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;
-
-       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;
+       struct file_lock *tmp;
+
+       /* 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 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 }
 
 /* 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 void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
 
 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 @@ static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx)
        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 @@ int get_locks_status(char *buf)
        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);
 }
index 183561dc0dc29f7b6715a91ac87cd90927fb5817..b779e483a5db93d64be1eaab084104fc747a4b5c 100644 (file)
@@ -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;
 }
index 6764b2be7ad7958a95ac96045c1f74737be8f9dc..47c029a9a2e4fc7191da2d090b7d0f45beaaaf88 100644 (file)
@@ -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 @@ struct inode_operations minix_file_inode_operations = {
        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;
index 2b1c0c0c56b488f1cbf262730d7c3b7c0a9d2e86..e4f6863d01f305aa8d33f352b5767d9edfa73263 100644 (file)
@@ -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 @@ extern struct timezone sys_tz;
 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). */
index d2f32f94c4a462f3141824b8f85daeef10ae5a34..708519827cff56d856a97234967b10f3d87a72e5 100644 (file)
@@ -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 @@ static int nfs_dir_open(struct inode * dir, struct file * file)
        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;
 }
index 85a258b820f8d5231a3e485f1497e887ec732dff..8e7dc8c0cbbe219de2cc964cf9e99e2371056226 100644 (file)
@@ -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 inline void revalidate_inode(struct nfs_server * server, struct inode * i
 }
 
 
-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 @@ static int nfs_fsync(struct inode *inode, struct file *file)
        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 @@ static int nfs_file_write(struct inode *inode, struct file *file, const char *bu
                        inode->i_mode);
                return -EINVAL;
        }
-       if (count <= 0)
+       if (count == 0)
                return 0;
 
        pos = file->f_pos;
index 64636c38bc8d51ca4094c58b7d80b38ac82b3722..c54b9770150853c04f3af064a3d36658d54c12c4 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -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 @@ static int pipe_read(struct inode * inode, struct file * filp, char * buf, int c
        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 @@ static int pipe_write(struct inode * inode, struct file * filp, const char * buf
        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 @@ static int fifo_select(struct inode * inode, struct file * filp, int sel_type, s
  * 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;
index 34bed13d64c08ad5c8762cf61a3c8333b313ce54..dcb4180a7b8c8e60429d985da25a215b5d00156c 100644 (file)
@@ -59,7 +59,8 @@ int get_malloc(char * buffer);
 #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 @@ static int read_core(struct inode * inode, struct file * file,char * buf, int co
 
        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 @@ struct inode_operations proc_kcore_inode_operations = {
  * 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 @@ static int read_profile(struct inode *inode, struct file *file, char *buf, int c
 }
 
 /* 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 @@ static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned
                ++*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 @@ static int get_statm(int pid, char * buffer)
 #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_locks_status (char *);
 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 @@ static inline int fill_array(char * page, int pid, int type, char **start, off_t
 
 #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 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
        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,14 +1167,12 @@ struct inode_operations proc_array_inode_operations = {
        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:
                        return read_maps(pid, file, buf, count);
index 941594eb098a97eb3e6648aa094409c745483273..8b58cb13be193a5d7da104752a47a161b2a4df79 100644 (file)
@@ -28,7 +28,8 @@ static void kmsg_release(struct inode * inode, struct file * file)
        (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);
 }
index 771d98a8fe90f61b512d72d97bef530355872678..c3c9b2db4358a2660083f7310a0870210d3c2966 100644 (file)
@@ -76,7 +76,8 @@ static struct task_struct * get_task(int pid)
        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 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
        char *tmp;
        int i;
 
-       if (count < 0)
-               return -EINVAL;
        tsk = get_task(inode->i_ino >> 16);
        if (!tsk)
                return -ESRCH;
@@ -134,7 +133,8 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
 
 #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 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
        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 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
 
 #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:
index e3cc7973c8884df7c286193a080806135f49ac20..6d6c7dda76f35ddec13545c943abb0a4d1bf8367 100644 (file)
@@ -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;
index 8c59fc177a614f25b3bba1cebe7b5c6c8cc11862..904d526f5bf27b836e7903d9ae69f081b1e77917 100644 (file)
 #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 @@ int get_not_present_info(char *buffer, char **start, off_t offset, int length)
                                      * 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 @@ static int proc_readscsi(struct inode * inode, struct file * file,
     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 @@ static int proc_readscsi(struct inode * inode, struct file * file,
        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_readscsi(struct inode * inode, struct file * file,
 }
 
 
-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_writescsi(struct inode * inode, struct file * file,
 }
 
 
-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 @@ static int proc_scsilseek(struct inode * inode, struct file * file,
     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);
     }
index 05ec1470cfd05d5cd63471c31155b72e8594d70c..78d5c1b10ae4fb44150e5ac43135204f1cf7c96d 100644 (file)
@@ -25,8 +25,8 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
                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 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
                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 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
        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 @@ bad_file:
        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 @@ bad_file:
        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 @@ static int sock_readv_writev(int type, struct inode * inode, struct file * file,
                (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 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file,
        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 @@ asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long cou
        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;
index aa435503c4b7a044a14bc0a629caae24e6c56d23..abe477fbd67f7d99c16a217b995a09e508a563b7 100644 (file)
@@ -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 @@ struct inode_operations smb_dir_inode_operations =
 };
 
 
-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;
 }
index 2e492559552000a784ca37c5f045ef66e091c142..9a9bb552c7c6d79c21cd8c3ac149d2bee5cd9514 100644 (file)
@@ -63,8 +63,8 @@ smb_make_open(struct inode *i, int right)
         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 @@ smb_file_read(struct inode *inode, struct file *file, char *buf, int count)
         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 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf,
 
         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)
index 1b4b777c56e3b65c324efc5cb9c52b84c4e6eb39..f32ceac095eaacf8bfb535b431e1cff05ba93d56 100644 (file)
@@ -170,13 +170,15 @@ extern struct timezone sys_tz;
 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). */
index 1d0038644944bcba3e156880fa9aba5695891de6..8cece496ee00a0e2bacf3bacb94d078f42f546d1 100644 (file)
@@ -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;
 }
index 92175ac7370af9cd0b7afe4c1ffaaf1bdcf7300e..e8e42e5d586346e6289678137e609f5a3f3165f9 100644 (file)
@@ -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 @@ struct inode_operations sysv_file_inode_operations = {
        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 @@ int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int cou
        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;
index 55211c8270e93d7f1d03056da6a136bc51c52b92..0abc12d36054c56c649fea0562a0953f076955ef 100644 (file)
@@ -27,8 +27,8 @@ extern struct inode *pseudo_root;
 /*
        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;
 }
index 7e5b4584678849824367c693a449c3b0b6ce18f8..075d4abc8d366b3bf0f94b342a4601941171ce01 100644 (file)
 /*
        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 @@ static int UMSDOS_file_read(
 /*
        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);
 }
index 2de9845d40a3cf1f86c355f05686d22717cc4304..e69acf2e2a5c3af1fa361c88b55124689f9528f1 100644 (file)
@@ -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;
index ba65f0a9575d7d4a20fc18fb91f9a0a9043942e4..148420e86a930adae62d6a53f356dffe076284cc 100644 (file)
@@ -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 @@ struct inode_operations xiafs_dir_inode_operations = {
     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;
 }
index bd5f8d36ecfdc3359a959e00aa7e864faae34e78..51c46cf0c10be4a1665d8a96428cd3f64c575b66 100644 (file)
@@ -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 @@ struct inode_operations xiafs_file_inode_operations = {
     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 @@ xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     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;
index e80373c87c6e2fda230748d12e6430510f06d440..3df5edf2bedc4033d833d379fa018fd91dac7507 100644 (file)
                                   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;
index 27013a9ecdcfbdd76c5f4b75e233419866ca7897..b9471de7bdc08a104803044fbcce6245cdc037e6 100644 (file)
@@ -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)
index 44fea065e27a0f4cf8deed02f92aa43bde2d9fdb..9cad208ceaa8e8c5bf6bdde7dca1043a96038ce6 100644 (file)
@@ -152,7 +152,19 @@ extern void                _writel(unsigned int b, unsigned long addr);
 /*
  * 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
@@ -203,6 +215,22 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
 
 #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__ */
 
 #endif
index 44306b82921f705d5f159fbcf0bde4d0b7aaa278..629e64e33741a39ed926f5dd8b7a10d15eea97d0 100644 (file)
@@ -52,7 +52,9 @@ typedef unsigned long pgprot_t;
 #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__ */
 
index 8ea7269d183893850df828c67a1146721ea5b658..937700caf88bb045a0f9f50e1ddacabfa791e72b 100644 (file)
@@ -266,8 +266,6 @@ extern unsigned long __zero_page(void);
 #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 unsigned long high_memory;
 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 int pte_present(pte_t pte)  { return pte_val(pte) & _PAGE_VALID; }
 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; }
 
index 8b64642ebad6293d740647daea3a9a7a9d301d7e..ac7d1a376effd4940358883361e3b8056250deed 100644 (file)
@@ -3,80 +3,22 @@
 
 #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 @@ static inline unsigned long __get_user(const void * y, int size)
 #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
index ac49b14007d48339d1af0372b81eb233c0230d13..5fb77913292be8e074a5fa47103c4d5ce1ad3f05 100644 (file)
@@ -27,13 +27,10 @@ unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
 
 
 /*
- * 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,
index 0704bdc3baa860bdaf3c5480f76f101d3b0b1160..ab48c55d59f9db11c370c68141346a76cd98aa55 100644 (file)
@@ -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 */
index 8db6b6070c0b3d7154a6296cd074a4f9f8c9546c..369ac5153b7b37d1b1d305b818b78cea68886d63 100644 (file)
                                   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;
index 1ba9056204811201f35d4bfbf9953739ae4449be..17f0b333d636f63434bb9bef6d043abffc27c790 100644 (file)
@@ -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 @@ static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
                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 @@ static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
                        st = inb(virtual_dma_port+4);
                }
                virtual_dma_count = lcount;
-               virtual_dma_addr = (int) lptr;
+               virtual_dma_addr = lptr;
        }
 #endif
 
@@ -168,7 +169,12 @@ static void vdma_set_dma_mode(unsigned int dummy,char mode)
        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 @@ struct fd_routine_l {
        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 @@ struct fd_routine_l {
                free_dma,
                clear_dma_ff,
                set_dma_mode,
-               set_dma_addr,
+               hset_dma_addr,
                set_dma_count,
                get_dma_residue,
                request_irq,
index 98e32ce68783b288fc03684d82f3050ff930d531..0dc907bfe36eea541533f0ce85b5ba03cefee53c 100644 (file)
 #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 @@ extern inline void * phys_to_virt(unsigned long address)
  * 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 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((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 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..
@@ -210,4 +216,20 @@ __OUTS(l)
        __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
index 61c9d19bbd18076cad19163cc4eb743ce4444cf1..69310caa26700428388104df8cf2f76fcadcbbdb 100644 (file)
@@ -21,7 +21,10 @@ extern void enable_irq(unsigned int);
 
 #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 @@ extern void enable_irq(unsigned int);
        "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 @@ extern void enable_irq(unsigned int);
        "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 @@ extern void enable_irq(unsigned int);
        "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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        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 --git a/include/asm-i386/ldt.h b/include/asm-i386/ldt.h
new file mode 100644 (file)
index 0000000..84440bf
--- /dev/null
@@ -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
index f315634618b9793d27fa814372f39aebb845b1ae..73b1cd81662b8824bddab09292c49c331cd09913 100644 (file)
@@ -54,8 +54,10 @@ typedef unsigned long pgprot_t;
 #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__ */
 
index 7b0bae22022f0c395b470669a6401fa95470306d..b3d793967cd2f0b110ee0e905ef6911d5a5946bd 100644 (file)
@@ -197,8 +197,8 @@ static inline void flush_tlb_range(struct mm_struct *mm,
  * 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 @@ static inline void flush_tlb_range(struct mm_struct *mm,
 #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 @@ extern pte_t * __bad_pagetable(void);
 /* 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 @@ do { \
 #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 @@ extern inline pte_t pte_mkyoung(pte_t pte)        { pte_val(pte) |= _PAGE_ACCESSED; ret
  * 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 @@ extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 }
 
 /* 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 @@ extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
                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 @@ getnew:
        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 @@ freenew:
 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;
 }
 
index 7f6da89fb7e67d3816466f191454c7dc4299959d..bb53f5ce703880fe7db1e65466cd2fb95cbf61c3 100644 (file)
@@ -104,7 +104,7 @@ struct thread_struct {
        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 @@ struct thread_struct {
        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 @@ struct thread_struct {
 #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.
index 6052ad459f558697b8f9cb88e9ba282cb910ab78..010d14c220f84253d3e9d58cf0e5bd770ed18776 100644 (file)
 
 #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 @@ __asm__("cld\n\t" \
  * 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__ */
index dc012f77a8f8288d0e2ebd56ba54cce9eec6f726..cef63f6fe0bd14f6cc8c4ecf89815cf6a4eae8dd 100644 (file)
@@ -96,6 +96,7 @@ __asm__("pushl %%edx\n\t" \
                loaddebug(prev,2); \
                loaddebug(prev,3); \
                loaddebug(prev,6); \
+               loaddebug(prev,7); \
        } \
 } while (0)
 
@@ -117,6 +118,7 @@ __asm__("movl %2,"SYMBOL_NAME_STR(current_set)"\n\t" \
                loaddebug(prev,2); \
                loaddebug(prev,3); \
                loaddebug(prev,6); \
+               loaddebug(prev,7); \
        } \
 } while (0)
 #endif
@@ -275,7 +277,7 @@ __asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
        "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)) \
        )
 
index b55dd003c01af721a4254a4f2b5eb3cec824b097..f8268fa7dea9f862a91fd6d72473f8b2da0d9eb4 100644 (file)
@@ -195,6 +195,7 @@ struct CIA {
 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 */
index 64ac1951473c6d9e15b4691c064727592c0b2bd6..0c225ee7ce8a628a3e3f2144405c8397c9eef2e6 100644 (file)
@@ -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)
 #define IRQ_AMIGA_RBF      (IRQ_MACHSPEC | 9)
 #define IRQ_AMIGA_TBE      (IRQ_MACHSPEC | 10)
 
+/* software interrupts */
+#define IRQ_AMIGA_SOFT      (IRQ_MACHSPEC | 11)
+
+/* interrupts from external hardware */
+#define IRQ_AMIGA_PORTS            (IRQ_MACHSPEC | 12)
+#define IRQ_AMIGA_EXTER            (IRQ_MACHSPEC | 13)
+
 /* 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)
-
-#define IRQ_AMIGA_SOFT      (IRQ_MACHSPEC | 21)
-
-#define IRQ_AMIGA_PORTS            (IRQ_MACHSPEC | 22)
-#define IRQ_AMIGA_EXTER            (IRQ_MACHSPEC | 23)
+#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
 
 #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 --git a/include/asm-m68k/atari_acsi.h b/include/asm-m68k/atari_acsi.h
new file mode 100644 (file)
index 0000000..31a882f
--- /dev/null
@@ -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 */
index b32f80cafe30618d06cd4fd4ffcf6e133acc94a8..2e6390f1dd07c616c2f4e9eda09f913b1e40ff16 100644 (file)
@@ -29,6 +29,6 @@ struct rootsector
   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 */
index d2cc3b7df5cc5d6ca473416d4183f4f48016e17b..ddc92e199ced5496a4bc99170f9bc03091619af6 100644 (file)
@@ -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 );
index 868e3fda6a80cd9e93e093b6e4deda624e6efa2a..3fccb4775a9e185b34bb57c013179876c0530da2 100644 (file)
@@ -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 @@ static inline void dma_cache_maintenance( unsigned long paddr,
 
 {
        if (writeflag) {
-               if (!is_medusa || m68k_is040or060 == 6)
+               if (!is_medusa || CPU_IS_060)
                        cache_push( paddr, len );
        }
        else {
@@ -273,9 +277,47 @@ struct TT_5380 {
 
 /* 
 ** 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 @@ struct SCC
  };
 # 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 @@ struct VIDEL_PALETTE
 
 /*
 ** 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
index ee3f5c632c5b76229c893fe33a7211ad971262b2..e2bb42b4ccb58ef06ce0d728ae57fa7fc31e9485 100644 (file)
@@ -216,5 +216,6 @@ extern inline int atari_irq_pending( unsigned irq )
 }
 
 unsigned long atari_register_vme_int( void );
+void atari_unregister_vme_int( unsigned long );
 
 #endif /* linux/atariints.h */
index 498ec2b4738a3206ac7dc99cf4e3a36850b976cb..b63496040fe6c71200fb250cb8050272a9515400 100644 (file)
@@ -59,11 +59,11 @@ extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size)
        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 @@ minix_find_first_zero_bit (const void *vaddr, unsigned size)
        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 @@ ext2_find_first_zero_bit (const void *vaddr, unsigned size)
        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;
@@ -239,4 +239,19 @@ ext2_find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
        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 --git a/include/asm-m68k/bootinfo.h b/include/asm-m68k/bootinfo.h
deleted file mode 100644 (file)
index 4685f8a..0000000
+++ /dev/null
@@ -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 */
index 1e01aa5a00e19a43e549411aa3ba3ec36bad1b4d..7f82a8c91c46abc657feb0e51d6f122c6b55d516 100644 (file)
@@ -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
index 1e4af6180574a3ef4123e3b4073e4623433f7365..731dd0b1afdabf9afc3b42eb7b2f79ed9989123f 100644 (file)
@@ -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 __delay(int loops)
  */
 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;
 }
 
index b5698efd2e61733814b25225f33929c812ddfb90..de8949f5633844b1f1dcf472e5400ff5b6e0ee02 100644 (file)
@@ -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 */
index fa40da33589db0aa25fffd5c9562a3834708804d..c1f6ea405a0af31181f472e8574053229a8febd9 100644 (file)
                                   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;
index 3a67bab4d760872d79ed20c3faa45e0cf62a04e3..385aa8c7f6ccc8a38e983d530be8e248bbce8c3a 100644 (file)
@@ -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.
  */
index 6d942ce265d5fcbc2ff14c3a7ea3ef51696ff689..7789be42f9fbfca3884b1b8ad16ae11cf2630b6d 100644 (file)
@@ -6,6 +6,12 @@ extern void enable_irq(unsigned int);
 
 #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.
@@ -13,9 +19,9 @@ extern void enable_irq(unsigned int);
  * 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 @@ extern void enable_irq(unsigned int);
  * 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 @@ extern void enable_irq(unsigned int);
  * The machine specific files define these sources.
  */
 
-#define IRQ_MACHSPEC    (0x10000000L)
-
-#ifndef ISRFUNC_T
-struct pt_regs;
-typedef void (*isrfunc) (int irq, struct pt_regs * regs, void *data);
-#define ISRFUNC_T
-#endif /* ISRFUNC_T */
-
-/*
- * 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;
-
-/* count of spurious interrupts */
-extern volatile unsigned long num_spurious;
+#define IRQ_MACHSPEC   (0x10000000L)
+#define IRQ_IDX(irq)   ((irq) & ~IRQ_MACHSPEC)
 
 /*
- * This function returns a new isr_node_t
+ * various flags for request_irq()
  */
-extern isr_node_t *new_isr_node(void);
+#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 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.
+ * This structure is used to chain together the ISRs for a particular
+ * interrupt source (if it supports chaining).
  */
-extern int remove_isr (unsigned long source, isrfunc isr, void *data);
+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 routine will insert an isr_node_t into a chain of nodes, using
- * the priority stored in the node.
+ * This structure has only 4 elements for speed reasons
  */
-extern void insert_isr (isr_node_t **listp, isr_node_t *node);
+typedef struct irq_handler {
+       void            (*handler)(int, void *, struct pt_regs *);
+       unsigned long   flags;
+       void            *dev_id;
+       const char      *devname;
+} irq_handler_t;
 
-/*
- * 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);
+/* count of spurious interrupts */
+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_ */
index ba4cd9d5b0fd60999a0f8553f4564537039ed98e..68302fe609193f86651e0977197a0c15b89f5843 100644 (file)
@@ -8,24 +8,22 @@ struct hwclk_time;
 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);
index b03fc345a13bc11dbd75619e78f03cd4debb50df..783ea2527867ac3c5419fb026f3e6c43d93ad3aa 100644 (file)
@@ -50,10 +50,6 @@ typedef unsigned long pgprot_t;
 
 #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 */
index 772bd0a89a30c3ff6af81e96ea8c0d8396232dea..252f01cc0e6f310359b8d1aa18c52d88d84031ce 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _M68K_PGTABLE_H
 #define _M68K_PGTABLE_H
 
+#include<asm/setup.h>
+
 #ifndef __ASSEMBLY__
 
 /*
  * 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 @@ static inline void __flush_tlb_one(unsigned long addr)
 }
 
 #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 @@ static inline void flush_tlb_range(struct mm_struct *mm,
  * 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 @@ typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
 #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 @@ extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
        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 pte_t * pte_offset(pmd_t * pmdp, unsigned long address)
 
 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 @@ extern inline void nocache_page (unsigned long vaddr)
 
 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 @@ extern inline pgd_t * pgd_alloc(void)
 
 #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 @@ extern void cache_push_v (unsigned long vaddr, int len);
    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 @@ extern void cache_push_v (unsigned long vaddr, int len);
 
 #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 void cache_push_v (unsigned long vaddr, int len);
 
 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 @@ extern inline void flush_cache_range(struct mm_struct *mm,
                                     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 @@ extern inline void flush_cache_page(struct vm_area_struct *vma,
                                    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 @@ extern inline void flush_cache_page(struct vm_area_struct *vma,
 /* 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 @@ extern inline void flush_page_to_ram (unsigned long address)
 /* 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"
index ae79964b8f1ce91e53302a7313cf37f3857ea665..2f1d561befc905175c12c992270f08032d12dc25 100644 (file)
@@ -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 @@ typedef long long    __kernel_loff_t;
 #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
index a87ab5bf1f48937af570386673a7759069592197..89f369017b181be8592d2ca1308ea0068601ead9 100644 (file)
@@ -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 @@ struct thread_struct {
        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 @@ struct thread_struct {
        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))
 
 /*
index 9fb04c7127ba5a045285ca632b15b831c29f9024..f94ce2708dfb318226f9f9057bff1c690ef256f4 100644 (file)
@@ -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}  \
 }
 
index ae848a16ce2d248f6b6eaabe83771d1eaaf7d6ca..f375cc977108408b668e9b3ffc907e12c0b7d213 100644 (file)
@@ -138,18 +138,18 @@ static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned
        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 @@ static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned
                         "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 @@ static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigne
        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 @@ static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigne
                         "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 --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h
new file mode 100644 (file)
index 0000000..ddb7180
--- /dev/null
@@ -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 --git a/include/asm-m68k/setup.h b/include/asm-m68k/setup.h
new file mode 100644 (file)
index 0000000..96f9196
--- /dev/null
@@ -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 */
index 11fa875f712ffe590f69f6aef54cc7a046e3efdb..57f83e3fcb6651ff779e022aeefccb4280f20847 100644 (file)
@@ -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 @@ extern inline int strncmp(const char * cs,const char * ct,size_t count)
 }
 
 #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 @@ extern inline void * memset(void * s,int c,size_t count)
       s = cs;
       count--;
     }
-  c |= c << 8;
   if (count > 2 && (long) s & 2)
     {
       short *ss = s;
@@ -214,7 +267,6 @@ extern inline void * memset(void * s,int c,size_t count)
   if (temp)
     {
       long *ls = s;
-      c |= c << 16;
       temp--;
       do
        *ls++ = c;
@@ -235,10 +287,141 @@ extern inline void * memset(void * s,int c,size_t count)
   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
index 242027ac9ca3c12a1b2a689bf083d47f495a4e1e..58c8d3905585373703e6f40751c6c4e6affa1466 100644 (file)
@@ -40,13 +40,20 @@ extern inline void wrusp(unsigned long usp) {
  * 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 @@ __asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory")
 
 #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;
index ad911a94b54d98cd0e3fc8c8f255ad7de1692f8e..265494aec39b404ecb13f5a5265ed715b90c3bf9 100644 (file)
@@ -437,6 +437,10 @@ static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long f
 {
        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 @@ static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long f
             "r" (arg), "a" (fn), "d" (clone_arg)
           : "d0", "d2");
 
+       set_fs (fs);
        return retval;
 }
 
index b4832760b6007648d402427bdaedc93fb693c6c1..b46acff494c350556b51e0ce9b4325e1dff77f6b 100644 (file)
  * 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 */
 #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 */
 #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 */
                                           GVP products - use the epc to
                                           identify it correctly */
 #define PROD_GVP_A2000_030     (0x0D)  /* GVP A2000 68030 Turbo Board */
+#define PROD_IMPACT_3001_IDE_2 (0x0D)  /* Impact 3001 IDE */
 #define PROD_GFORCE_040_SCSI   (0x16)  /* GForce 040 with SCSI (new) */
 #define PROD_GVPIV_24          (0x20)  /* GVP IV-24 Graphics Board */
+#define PROD_GFORCE_040        (0xFF)  /* GForce 040 Turbo Board */
 /* #define PROD_GVPIO_EXT      (0xFF)*/        /* GVP I/O Extender */
 
+#define MANUF_SYNERGY          (0x07E5)        /* Synergy */
+
+#define MANUF_XETEC            (0x07E6)        /* Xetec */
+#define PROD_FASTCARD_SCSI     (0x01)  /* FastCard SCSI Controller */
+#define PROD_FASTCARD_RAM      (0x02)  /* FastCard RAM */
+
 #define MANUF_PPI              (0x07EA)        /* Progressive Peripherals Inc. */
 #define PROD_MERCURY           (0x00)  /* Mercury Turbo Board */
 #define PROD_PPS_A3000_040     (0x01)  /* PP&S A3000 68040 Turbo Board */
 #define PROD_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 */
 #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 */
 #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 */
 #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 */
 #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,
index 223967ae456e5384f854610d3a96a7a78b4500a5..13fa713402548703c3eee6b16146d08a36ce92cb 100644 (file)
                                   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;
index 8ebf818fe41e3381e084f3f21f757f86b4010a6a..48331ca9d006c90fafac3de14c1325ae729fec2a 100644 (file)
@@ -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()
index 61d0fa703f745249b8087ee4e1e7eb04888d89c4..9b0f41c73cf61e2fe070d9d65bfbdb4f1d36b437 100644 (file)
                                   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;
index d36d35eb1c78dac78950bf2570dafe97165ff3b6..eb52f46117862c50e5563d5474e6e49cfa0a6cb3 100644 (file)
@@ -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)
index de42f13046e8300850499879ccff940df8aa9305..f3a3b859c394493b454ab7c6a1d2ffb4e3dc4a16 100644 (file)
                                   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;
index 97cb4ee0b65a9e185fbe4f488f0cf62077ce034c..6f92e0fe81edf63fd2aba33701d073e777b2ca6f 100644 (file)
@@ -336,16 +336,22 @@ struct file {
        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 @@ struct super_block {
 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 * bread(kdev_t dev, int block, int size);
 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 kdev_t real_root_dev;
 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 --git a/include/linux/ldt.h b/include/linux/ldt.h
deleted file mode 100644 (file)
index 84440bf..0000000
+++ /dev/null
@@ -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
index 8aad25d8d625d27bceb4d45fd143ac25be03d51e..201fa17312ca9386b9ff7017d751b9a754b15023 100644 (file)
@@ -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>
@@ -275,13 +276,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,
        unsigned long prot, unsigned long flags, unsigned long off);
index 63a630472e966cb90dd6c13eb349021d63134f75..7aef08e01df5dc1f7d8805811baf9e7d7b7a4070 100644 (file)
@@ -221,8 +221,8 @@ extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
 /* 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 */
index 3eed501c4765e33f52931bb4685a4ca4db98fa83..7b19dac3cf6cbb7323dd952bf91e5ff02cb7f06e 100644 (file)
@@ -385,7 +385,7 @@ extern int sysv_bmap(struct inode *,int);
 
 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 *);
index c27f374d54dac0e4652dc09f554cf38c1b2f2020..333f9940f7d6727527308b1b21ec818b98e3c9b8 100644 (file)
@@ -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 @@ int UMSDOS_lookup (struct inode *dir,
         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 --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
new file mode 100644 (file)
index 0000000..7fc9731
--- /dev/null
@@ -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 --git a/include/linux/xd.h b/include/linux/xd.h
deleted file mode 100644 (file)
index 45cce2e..0000000
+++ /dev/null
@@ -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 */
index 9b8ba7a0b2c01464e4e0575b66b32fe84e3cbeee..f23800901c638a983f1ce629f5c6eed694b3e361 100644 (file)
@@ -28,9 +28,9 @@ typedef struct
 
 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
index 5e5459164386a00bf74f8d15753645da4ae36d70..8922277d623b13a0fdf7d66fb5545c9251e43852 100644 (file)
@@ -98,6 +98,7 @@ extern void wd7000_setup(char *str, int *ints);
 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 @@ struct {
 #ifdef CONFIG_BUGi386
        { "no-hlt", no_halt },
        { "no387", no_387 },
+       { "reboot=", reboot_setup },
 #endif
 #ifdef CONFIG_INET
        { "ether=", eth_setup },
index 52e434285f5785d0ee06f636384648aa7d0af97d..ee5cdd5a8e3d4571e11ced1b90a591ad9bd698ad 100644 (file)
@@ -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 @@ static inline int dup_mmap(struct mm_struct * mm)
                        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;
        }
index b938d82da3d9f639358b684bccd89d3ee0ce02d0..650271d834ca99472ce50f3948be62a7bdcd2e62 100644 (file)
@@ -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 @@ struct symbol_table symbol_table = {
        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),
 
index 04c3d7f8c026921cf919b6d4e75deb5854e1bfff..ebcf6a1cd60245ee07f18495cebeac8436186d81 100644 (file)
@@ -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...)
index 3365a6b3792dbc2565728f635bc6f88066bd2677..254c8bf8e1e62305d656e6361b43dacba021a1fa 100644 (file)
@@ -46,10 +46,10 @@ extern ctl_table net_table[];
 
 #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 void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root
 }
 
 
-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 @@ static int do_rw_proc(int write, struct inode * inode, struct file * file,
        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);
 }
index ead0b329a0cb7a96376b18799b963cf22256c7c7..7626e4d22a65d3e13c660c7465108b0bddbd8948 100644 (file)
@@ -129,7 +129,7 @@ int shrink_mmap(int priority, int dma)
 {
        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 @@ static inline unsigned long generic_file_readahead(int reada_ok, struct file * f
  * 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;
index 6ae27e20fb60c3e93c107506104b1f6a91298480..16fceb8e5b52b35d8a98adea57766eb6ef575f10 100644 (file)
@@ -405,7 +405,7 @@ void kfree(void *__ptr)
                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();
index 982da5847440a1200e901a8f2db263cf9619663d..b9007738282f1707815ab741b5738ad27d6ea1dc 100644 (file)
@@ -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 @@ static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)
                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 @@ static inline void free_pte(pte_t page)
 {
        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 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
  * 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 @@ static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned
        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 @@ static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned l
        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 @@ int remap_page_range(unsigned long from, unsigned long offset, unsigned long siz
                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 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
        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 @@ void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
        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 @@ static void partial_clear(struct vm_area_struct *vma, unsigned long address)
        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));
index 0f712014daf1e0d69fe07d8d1c828a6cc3475614..a57cc06d4bf106e007afdcca8f01c6e31dbc08bc 100644 (file)
@@ -202,7 +202,7 @@ asmlinkage int sys_mlock(unsigned long start, size_t len)
 
        /* 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 @@ asmlinkage int sys_mlockall(int flags)
 
        /* 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);
index 6b6cfbb79ea7645f3f69f29ca141bfca969eebd5..69e4d402e36388dc2edeca1a651b128672af8aab 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -58,7 +58,7 @@ static inline int vm_enough_memory(long pages)
        freepages >>= 1;
        freepages += nr_free_pages;
        freepages += nr_swap_pages;
-       freepages -= MAP_NR(high_memory) >> 4;
+       freepages -= max_mapnr >> 4;
        return freepages > pages;
 }
 
index 781e5bcf6b118420a96cf9478bcaf3b6f1dad2ac..12a0058a99f1701d41d5b010ebd7cab277d38188 100644 (file)
@@ -135,7 +135,7 @@ void free_pages(unsigned long addr, unsigned long order)
 {
        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;
index 81bf2f4ffb59ad2b2a1b8346e47407d9bb166b4d..fb980004f3d379eec5c55a600570704dcd4ce44c 100644 (file)
@@ -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 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
                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;
index c61c779d178b54d96c252d30509c36c969c99866..26dcb59e1982e38719fd3366aadf44c8943ac73a 100644 (file)
@@ -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 @@ static int alloc_area_pages(unsigned long address, unsigned long size)
        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 @@ void * vmalloc(unsigned long size)
        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 @@ void * vmalloc(unsigned long size)
        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 @@ int vread(char *buf, char *addr, int count)
                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 @@ int vread(char *buf, char *addr, int count)
                while (--n >= 0) {
                        if (count == 0)
                                goto finished;
-                       put_user(*addr++, buf++), count--;
+                       put_user(*addr, buf);
+                       buf++;
+                       addr++;
+                       count--;
                }
        }
 finished:
index 7e467bdd995cdf2f8d133fbf11d12b6c4d4b27b0..37627286cc587b74f80993d5d9a7b3fffcf9f052 100644 (file)
@@ -79,7 +79,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
        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);
index 47150376aa59797dcd864cfe71050d82effb179c..60ef256b3b2975b2e971ad982b815d2884989ce3 100644 (file)
@@ -1137,7 +1137,6 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */
                                                /* 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",
index e6cd8fad3b7929e086869926c22d0e9270940a5e..affe76c261c91c8590f0b467de4f549adde24176 100644 (file)
@@ -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 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, struct devi
                        default:
                                break;
                }
-               if(icmph->code>12)      /* Invalid type */
+               if(icmph->code>15)      /* Invalid type */
                        return;
        }
        
index 20b624a1c8c001b0338eaeb03e55537fcfe395be..17f4ea5cc4b0f154972826870bdf2a05cbdb1648 100644 (file)
 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 @@ void sock_release(struct socket *sock)
  *     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 @@ static int sock_lseek(struct inode *inode, struct file *file, off_t offset, int
  *     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 @@ static int sock_read(struct inode *inode, struct file *file, char *ubuf, int siz
  *     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;
index c8f513b264d4325ba004e0ecb8247757d143ec0f..fc2608113cb1fbc183af069fa62e06f824da3839 100644 (file)
@@ -57,25 +57,29 @@ static void handle_config(void)
 #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_line:
        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')