]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.3.7pre6 2.3.7pre6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:32 +0000 (15:25 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:32 +0000 (15:25 -0500)
Anybody who is interested in FS performance should take a look at the
latest pre-patch of 2.3.7 (only pre-6 and possibly later: do NOT get any
earlier versions. pre-5 still causes file corruption, pre-6 looks good so
far).

Careful, though: I fixed the problem that caused some corruption less than
an hour ago, and while my tests indicate it all works fine, this is a very
fundamental change. The difference to earlier kernels is:

 - ext2 (and some other block device filesystems that have been taught
   about it) uses write-through from the page cache instead of having a
   separate buffer cache and the page cache to maintain dirty state. This
   means much less memory pressure in certain situations, and it also
   means that we can avoid unnecessary copies.
 - the page cache has been threaded, so on SMP you can actually get
   noticeable speedups from processes that do concurrent file accesses.
 - lower-latency read paths, especially the cached case.

Both of these are big, and fundamental changes. So don't mistake me when I
say it is experimental: Ingo, David and I have been spending the last
weeks (especialy Ingo, who deserves a _lot_ of credit for this all: I
designed much of it, but Ingo made it a reality. Thanks Ingo) on making it
do the right thing and be stable, but if you worry about not having
backups you might not want to play with it even so. It took us this long
just to make it work reliably enough that we can't find any obvious
problems..

The interesting areas are things like
 - writes to shared mappings now go blindingly fast. We're talking mondo
   cleanups here. We used to do really badly on this, now we do really
   well.
 - does bdflush still do the right thing? There may be a _lot_ of tweaking
   to do to get everything working at full capacity.
 - can people confirm that it is stable for everybody?
 - if anybody has 8-way machines etc, scalability is interesting. It
   should scale to 8-way no problem. We used to scale to 1-way, barely.
   Numbers?
 - fsync(). It doesn't work right now, but it should be easy to make it
   work well on big files etc - something we've never been able to do
   before (we used to lack the indexing from file to dirty blocks: now we
   have access to that quite automatically thanks to having the
   inode->page index in place, and the dirty blocks are right there)

and I'd really appreciate comments from people, as long as people are
aware that it _looks_ stable but we don't guarantee anything at this
point.

                Linus

190 files changed:
Documentation/ARM-README [deleted file]
Documentation/Configure.help
Documentation/pci.txt
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/ll_char_wr.S [new file with mode: 0644]
arch/arm/config.in
arch/arm/defconfig
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/arthur.c [new file with mode: 0644]
arch/arm/kernel/calls.S
arch/arm/kernel/dec21285.c
arch/arm/kernel/dma-a5k.c
arch/arm/kernel/dma-arc.c
arch/arm/kernel/dma-dummy.c
arch/arm/kernel/dma-ebsa285.c [deleted file]
arch/arm/kernel/dma-footbridge.c [new file with mode: 0644]
arch/arm/kernel/dma-isa.c
arch/arm/kernel/dma-isa.h
arch/arm/kernel/dma-rpc.c
arch/arm/kernel/dma-vnc.c [deleted file]
arch/arm/kernel/dma.c
arch/arm/kernel/dma.h
arch/arm/kernel/ecard.c
arch/arm/kernel/entry-armo.S
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/fiq.c
arch/arm/kernel/head-armv.S
arch/arm/kernel/hw-ebsa285.c [deleted file]
arch/arm/kernel/hw-footbridge.c [new file with mode: 0644]
arch/arm/kernel/iic.c
arch/arm/kernel/init_task.c
arch/arm/kernel/ioport.c [deleted file]
arch/arm/kernel/irq.c
arch/arm/kernel/leds-ebsa110.c
arch/arm/kernel/leds-ebsa285.c [deleted file]
arch/arm/kernel/leds-footbridge.c [new file with mode: 0644]
arch/arm/kernel/oldlatches.c
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/sys_arm.c
arch/arm/kernel/time.c
arch/arm/kernel/traps.c
arch/arm/lib/Makefile
arch/arm/lib/checksum.S
arch/arm/lib/floppydma.S
arch/arm/lib/getconsdata.c
arch/arm/lib/io-acorn.S
arch/arm/lib/io-ebsa110.S
arch/arm/lib/io-ebsa285.S [deleted file]
arch/arm/lib/io-footbridge.S [new file with mode: 0644]
arch/arm/lib/io.c
arch/arm/lib/ll_char_wr.S [deleted file]
arch/arm/lib/semaphore.S [new file with mode: 0644]
arch/arm/mm/fault-common.c
arch/arm/mm/ioremap.c
arch/arm/mm/proc-arm2,3.S
arch/arm/mm/proc-arm6,7.S
arch/arm/mm/proc-sa110.S
arch/arm/nwfpe/ARM-gcc.h [new file with mode: 0644]
arch/arm/nwfpe/ChangeLog [new file with mode: 0644]
arch/arm/nwfpe/Makefile [new file with mode: 0644]
arch/arm/nwfpe/config.h [new file with mode: 0644]
arch/arm/nwfpe/double_cpdo.c [new file with mode: 0644]
arch/arm/nwfpe/entry.S [new file with mode: 0644]
arch/arm/nwfpe/entry26.S [new file with mode: 0644]
arch/arm/nwfpe/extended_cpdo.c [new file with mode: 0644]
arch/arm/nwfpe/fpa11.c [new file with mode: 0644]
arch/arm/nwfpe/fpa11.h [new file with mode: 0644]
arch/arm/nwfpe/fpa11.inl [new file with mode: 0644]
arch/arm/nwfpe/fpa11_cpdo.c [new file with mode: 0644]
arch/arm/nwfpe/fpa11_cpdt.c [new file with mode: 0644]
arch/arm/nwfpe/fpa11_cprt.c [new file with mode: 0644]
arch/arm/nwfpe/fpmodule.c [new file with mode: 0644]
arch/arm/nwfpe/fpmodule.h [new file with mode: 0644]
arch/arm/nwfpe/fpmodule.inl [new file with mode: 0644]
arch/arm/nwfpe/fpopcode.c [new file with mode: 0644]
arch/arm/nwfpe/fpopcode.h [new file with mode: 0644]
arch/arm/nwfpe/fpsr.h [new file with mode: 0644]
arch/arm/nwfpe/milieu.h [new file with mode: 0644]
arch/arm/nwfpe/single_cpdo.c [new file with mode: 0644]
arch/arm/nwfpe/softfloat-macros [new file with mode: 0644]
arch/arm/nwfpe/softfloat-specialize [new file with mode: 0644]
arch/arm/nwfpe/softfloat.c [new file with mode: 0644]
arch/arm/nwfpe/softfloat.h [new file with mode: 0644]
arch/arm/vmlinux-armv.lds
arch/i386/defconfig
arch/sparc/defconfig
arch/sparc/kernel/signal.c
arch/sparc/kernel/sys_sunos.c
arch/sparc64/defconfig
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/sys_sunos32.c
drivers/acorn/block/Config.in
drivers/acorn/block/Makefile
drivers/acorn/block/fd1772.c
drivers/acorn/block/fd1772dma.S
drivers/acorn/block/ide-ics.c [deleted file]
drivers/acorn/block/ide-rapide.c [deleted file]
drivers/acorn/block/mfm.S
drivers/acorn/block/mfmhd.c
drivers/acorn/char/Config.in [deleted file]
drivers/acorn/char/Makefile
drivers/acorn/char/keyb_arc.c [new file with mode: 0644]
drivers/acorn/char/keyb_ps2.c
drivers/acorn/char/mouse_rpc.c
drivers/acorn/char/serial-card.c
drivers/acorn/net/ether1.c
drivers/acorn/net/ether3.c
drivers/acorn/net/ether3.h
drivers/acorn/net/etherh.c
drivers/acorn/scsi/Config.in
drivers/acorn/scsi/Makefile
drivers/acorn/scsi/acornscsi.c
drivers/acorn/scsi/acornscsi.h
drivers/acorn/scsi/arxescsi.c [new file with mode: 0644]
drivers/acorn/scsi/arxescsi.h [new file with mode: 0644]
drivers/acorn/scsi/cumana_2.c
drivers/acorn/scsi/eesox.c
drivers/acorn/scsi/fas216.c
drivers/acorn/scsi/fas216.h
drivers/acorn/scsi/msgqueue.c
drivers/acorn/scsi/msgqueue.h
drivers/acorn/scsi/powertec.c
drivers/acorn/scsi/queue.c
drivers/block/Config.in
drivers/block/icside.c [new file with mode: 0644]
drivers/block/rapide.c [new file with mode: 0644]
drivers/net/Makefile
drivers/pci/pci.c
drivers/sbus/audio/cs4215.h
drivers/sbus/audio/dbri.c
drivers/sbus/audio/dbri.h
drivers/sbus/char/su.c
drivers/scsi/in2000.h
drivers/sound/vidc.c
drivers/sound/vidc_audio.c
drivers/sound/vidc_fill.S
drivers/sound/waveartist.c
drivers/sound/waveartist.h
drivers/video/acornfb.c
drivers/video/cyber2000fb.c
drivers/video/cyber2000fb.h
fs/buffer.c
fs/inode.c
fs/nfs/dir.c
fs/nfs/symlink.c
fs/super.c
include/asm-arm/arch-arc/ide.h
include/asm-arm/arch-ebsa285/ide.h
include/asm-arm/arch-ebsa285/irq.h
include/asm-arm/arch-ebsa285/memory.h
include/asm-arm/arch-ebsa285/system.h
include/asm-arm/arch-ebsa285/time.h
include/asm-arm/arch-rpc/ide.h
include/asm-arm/current.h
include/asm-arm/dma.h
include/asm-arm/ide.h
include/asm-arm/io.h
include/asm-arm/irq.h
include/asm-arm/proc-armo/ptrace.h
include/asm-arm/proc-armo/semaphore.h
include/asm-arm/proc-armo/system.h
include/asm-arm/proc-armv/ptrace.h
include/asm-arm/proc-armv/semaphore.h
include/asm-arm/proc-armv/system.h
include/asm-arm/processor.h
include/asm-arm/semaphore.h
include/asm-arm/softirq.h
include/asm-arm/spinlock.h
include/asm-arm/system.h
include/asm-arm/unistd.h
include/asm-sparc/namei.h
include/asm-sparc/page.h
include/asm-sparc/spinlock.h
include/asm-sparc64/elf.h
include/asm-sparc64/namei.h
include/asm-sparc64/page.h
include/asm-sparc64/spinlock.h
include/linux/blk.h
include/linux/fd1772.h [new file with mode: 0644]
include/linux/pagemap.h
include/linux/pci.h
mm/filemap.c

diff --git a/Documentation/ARM-README b/Documentation/ARM-README
deleted file mode 100644 (file)
index 62700e1..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-                          ARM Linux 2.1.99
-                          ================
-
-  Since this is a development kernel, it will not be as stable as the 2.0
-  series, and can cause very nasty problems (eg, trashing your hard disk).
-  When running one of these kernels, I advise you to back up the complete
-  contents of all your hard disks.
-
-
-Contributors
-------------
-
-  Here is a list of people actively working on the project (If you
-  wish to be added to the list, please email me):
-
-  Name: Russell King
-  Mail: linux@arm.uk.linux.org
-  Desc: Original developer of ARM Linux, project co-ordinator.
-
-  Name: Dave Gilbert
-  Mail: linux@treblig.org
-  Desc: A3/4/5xx floppy and hard disk code maintainer.
-
-  Name: Philip Blundell
-  Mail: Philip.Blundell@pobox.com
-  Desc: Architecture and processor selection during make config.
-
-
-Todo list
----------
-
-  This is the list of changes to be done (roughly prioritised):
-
-  * fully test new MEMC translation code
-  * fully test new AcornSCSI driver.
-  * reply to email ;)
-
-
-                            Notes
-                            =====
-
-Compilation of kernel
----------------------
-
-  In order to compile ARM Linux, you will need a compiler capable of
-  generating ARM ELF code with GNU extensions.  GCC-2.7.2.2 is good.
-
-  To build ARM Linux natively, you shouldn't have to alter the ARCH = line in
-  the top level Makefile.  However, if you don't have the ARM Linux ELF tools
-  installed as default, then you should change the CROSS_COMPILE line as
-  detailed below.
-
-  If you wish to cross-compile, then alter the following lines in the top
-  level make file:
-
-    ARCH = <whatever>
-       with
-    ARCH = arm
-
-       and
-
-    CROSS_COMPILE=
-       to
-    CROSS_COMPILE=<your-path-to-your-compiler-without-gcc>
-       eg.
-    CROSS_COMPILE=/usr/bin/arm-unknown-linuxelf-
-
-  Do a 'make config', followed by 'make dep', and finally 'make all' to
-  build the kernel (vmlinux).  A compressed image can be built by doing
-  a 'make zImage' instead of 'make all'.
-
-
-Bug reports etc.
-----------------
-
-  Please send patches, bug reports and code for the ARM Linux project
-  to linux@arm.uk.linux.org.  Patches will not be included into future
-  kernels unless they come to me (or the relevant person concerned).
-
-  When sending bug reports, please ensure that they contain all relevant
-  information, eg. the kernel messages that were printed before/during
-  the problem, what you were doing, etc.
-
-  For patches, please include some explanation as to what the patch does
-  and why (if relevant).
-
-
-Modules
--------
-
-  Although modularisation is supported (and required for the FP emulator),
-  each module on an arm2/arm250/arm3 machine when is loaded will take
-  memory up to the next 32k boundary due to the size of the pages.  Hence is
-  modularisation on these machines really worth it?
-
-  However, arm6 and up machines allow modules to take multiples of 4k, and
-  as such Acorn RiscPCs and other architectures using these processors can
-  make good use of modularisation.
-
-
-ADFS Image files
-----------------
-
-  You can access image files on your ADFS partitions by mounting the ADFS
-  partition, and then using the loopback device driver.  You must have
-  losetup installed.
-
-  Please note that the PCEmulator DOS partitions have a partition table at
-  the start, and as such, you will have to give '-o offset' to losetup.
-
-
-Kernel initialisation abort codes
----------------------------------
-
-  When the kernel is unable to boot, it will if possible display a colour
-  at the top of the screen.  The colours have the following significance
-  when run in a 16 colour mode with the default palette:
-
-    Stripes of white, red, yellow, and green:
-       Kernel does not support the processor architecture detected.
-
-
-Request to developers
----------------------
-
-  When writing device drivers which include a separate assembler file, please
-  include it in with the C file, and not the arch/arm/lib directory.  This
-  allows the driver to be compiled as a loadable module without requiring
-  half the code to be compiled into the kernel image.
-
-  In general, try to avoid using assembler unless it is really necessary.  It
-  makes drivers far less easy to port to other hardware.
-
-
-ST506 hard drives
------------------
-
-  The ST506 hard drive controllers seem to be working fine (if a little
-  slowly).  At the moment they will only work off the controllers on an
-  A4x0's motherboard, but for it to work off a Podule just requires
-  someone with a podule to add the addresses for the IRQ mask and the
-  HDC base to the source.
-
-  As of 31/3/96 it works with two drives (you should get the ADFS
-  *configure hard drive set to 2). I've got an internal 20 MB and a great
-  big external 5.25" FH 64 MB drive (who could ever want more :-) ).
-
-  I've just got 240 K/s off it (a dd with bs=128k); that's about half of what
-  RiscOS gets, but it's a heck of a lot better than the 50 K/s I was getting
-  last week :-)
-
-  Known bug: Drive data errors can cause a hang; including cases where
-  the controller has fixed the error using ECC. (Possibly ONLY
-  in that case...hmm).
-
-
-1772 Floppy
------------
-  This also seems to work OK, but hasn't been stressed much lately.  It
-  hasn't got any code for disc change detection in there at the moment which
-  could be a bit of a problem!  Suggestions on the correct way to do this
-  are welcome.
-
-
-Kernel entry (head-armv.S)
---------------------------
-  The initial entry into the kernel made via head-armv.S uses architecture
-  independent code.  The architecture is selected by the value of 'r1' on
-  entry, which must be kept unique.  You can register a new architecture
-  by mailing the following details to rmk@arm.uk.linux.org.  Please give
-  the mail a subject of 'Register new architecture':
-
-    Name: <name of your architecture>
-    ARCHDIR: <name of include/asm-arm/arch-* directory>
-    Description:
-    <description of your architecture>
-
-  Please follow this format - it is an automated system.  You should
-  receive a reply the next day.
----
-Russell King (03/05/1998)
index 07439cbf281f110e2f037765054fa835c6fd959d..2caf07806ea6664a338e59375f76c12cdebed6aa 100644 (file)
@@ -11348,7 +11348,8 @@ Footbridge Mode
 CONFIG_HOST_FOOTBRIDGE
   The 21285 Footbridge chip can operate in either `host mode' or
   `add-in' mode.  Say Y if your 21285 is in host mode, and therefore
-  is the configuration master, otherwise say N.
+  is the configuration master, otherwise say N.  This must not be
+  set to 'Y' if the card is used in 'add-in' mode.
 
 MFM harddisk support
 CONFIG_BLK_DEV_MFM
index d40bfaf38ec2c85dc0aea4d4a05c4f8d815f27ba..4536c87da1cec576f215efe469d12bd6972662dc 100644 (file)
@@ -4,7 +4,7 @@
 
                "What should you avoid when writing PCI drivers"
 
-         by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on 13-Feb-1998
+         by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on 17-Jun-1999
 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -19,6 +19,10 @@ ID, it should use:
 
    For class-based search, use pci_find_class(CLASS_ID, dev).
 
+   You can use the constant PCI_ANY_ID as a wildcard replacement for
+VENDOR_ID or DEVICE_ID.  This allows searching for any device from a
+specific vendor, for example.
+
    In case you want to do some complex matching, look at pci_devices -- it's
 a linked list of pci_dev structures for all PCI devices in the system.
 
index 967ee67661c271bb930ddfc541fa7c6ef693d52b..1c198989dca507a7c0f26230e635eb01964fefe7 100644 (file)
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 1995, 1996 by Russell King
+# Copyright (C) 1995-1999 by Russell King
 
 CFLAGS_PROC            :=
 ASFLAGS_PROC           :=
 
-# All processors get `-mshort-load-bytes' for now, to work around alignment
-# problems.  This is more of a hack that just happens to work than a real fix
-# but it will do for now.
+# GCC 2.7 uses different options to later compilers; sort out which we have
+CONFIG_GCC_NEW         := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi)
+
+# Hack to get around RiscPC with StrongARM optimistaion
+# problem - force ARM710 optimisation for now.
+ifeq ($(CONFIG_GCC_NEW),y)
+  ifeq ($(CONFIG_ARCH_RPC),y)
+    ifeq ($(CONFIG_CPU_SA110),y)
+      CONFIG_CPU_SA110 := n
+      CONFIG_CPU_ARM7  := y
+    endif
+  endif
+endif
 
 ifeq ($(CONFIG_CPU_26),y)
   PROCESSOR             = armo
   TEXTADDR              = 0x02080000
   ZTEXTADDR             = 0x01800000
   ZRELADDR              = 0x02080000
-  ifeq ($(CONFIG_BINUTILS_NEW),y)
+  ifeq ($(CONFIG_GCC_NEW),y)
     CFLAGS_PROC                += -mapcs-26 -mshort-load-bytes
     ifeq ($(CONFIG_CPU_ARM2),y)
       CFLAGS_PROC      += -mcpu=arm2
@@ -49,7 +59,7 @@ endif
 ifeq ($(CONFIG_CPU_32),y)
   PROCESSOR             = armv
   TEXTADDR              = 0xC0008000
-  ifeq ($(CONFIG_BINUTILS_NEW),y)
+  ifeq ($(CONFIG_GCC_NEW),y)
     CFLAGS_PROC                += -mapcs-32 -mshort-load-bytes
     ifeq ($(CONFIG_CPU_ARM6),y)
       CFLAGS_PROC      += -mcpu=arm6
@@ -68,10 +78,11 @@ endif
 
 # Processor Architecture
 # CFLAGS_PROC - processor dependent CFLAGS
-# PROCESSOR - processor type
-# TEXTADDR - Uncompressed kernel link text address
-# ZTEXTADDR - Compressed kernel link text address
-# ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded).
+# PROCESSOR   - processor type
+# TEXTADDR    - Uncompressed kernel link text address
+# ZTEXTADDR   - Compressed kernel link text address
+# ZRELADDR    - Compressed kernel relocating address
+#              (point at which uncompressed kernel is loaded).
 #
 
 COMPRESSED_HEAD         = head.o
@@ -79,19 +90,16 @@ COMPRESSED_HEAD      = head.o
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE                 = a5k
 ARCHDIR                 = arc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
 ifeq ($(CONFIG_ARCH_ARC),y)
 MACHINE                 = arc
 ARCHDIR                 = arc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
 ifeq ($(CONFIG_ARCH_RPC),y)
 MACHINE                 = rpc
 ARCHDIR                 = rpc
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 ZTEXTADDR       = 0x10008000
 ZRELADDR        = 0x10008000
 endif
@@ -103,13 +111,17 @@ ZTEXTADDR  = 0x00008000
 ZRELADDR        = 0x00008000
 endif
 
-ifeq ($(CONFIG_ARCH_EBSA285),y)
-MACHINE                 = ebsa285
+ifeq ($(CONFIG_FOOTBRIDGE),y)
+MACHINE                 = footbridge
 ARCHDIR                 = ebsa285
 ZTEXTADDR       = 0x00008000
 ZRELADDR        = 0x00008000
 endif
 
+ifeq ($(CONFIG_ARCH_CO285),y)
+TEXTADDR        = 0x60008000
+endif
+
 ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
 MACHINE                 = nexuspci
 ARCHDIR                 = nexuspci
@@ -119,31 +131,13 @@ COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o
 COMPRESSED_HEAD         = head-nexuspci.o
 endif
 
-ifeq ($(CONFIG_ARCH_VNC),y)
-TEXTADDR        = 0xC000C000
-MACHINE                 = vnc
-ARCHDIR                 = vnc
-endif
-
-ifeq ($(CONFIG_ARCH_TBOX),y)
-MACHINE                 = tbox
-ARCHDIR                 = tbox
-ZTEXTADDR       = 0x80008000
-ZRELDIR                 = 0x80008000
-endif
-
 PERL            = perl
-ifeq ($(CONFIG_BINUTILS_NEW),y)
-LD              = $(CROSS_COMPILE)ld -m elf32arm
-else
-LD              = $(CROSS_COMPILE)ld -m elf_arm
-endif
+LD              = $(CROSS_COMPILE)ld
 OBJCOPY                 = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 OBJDUMP                 = $(CROSS_COMPILE)objdump
 CPP             = $(CC) -E
 ARCHCC         := $(word 1,$(CC))
 GCCLIB         := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name`
-#GCCARCH               := -B/usr/bin/arm-linuxelf- 
 HOSTCFLAGS     := $(CFLAGS:-fomit-frame-pointer=)
 ifeq ($(CONFIG_FRAME_POINTER),y)
 CFLAGS         := $(CFLAGS:-fomit-frame-pointer=)
@@ -153,75 +147,40 @@ ASFLAGS           := $(ASFLAGS_PROC) $(ASFLAGS)
 LINKFLAGS       = -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -Ttext $(TEXTADDR)
 ZLINKFLAGS      = -Ttext $(ZTEXTADDR)
 
-SUBDIRS                := $(SUBDIRS:drivers=arch/arm/drivers) arch/arm/lib arch/arm/kernel arch/arm/mm
-HEAD           := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
+# If we're intending to debug the kernel, make sure it has line number
+# information.  This gets stripped out when building (z)Image so it doesn't
+# add anything to the footprint of the running kernel.
+ifeq ($(CONFIG_DEBUG_INFO),y)
+CFLAGS         += -g
+endif
+
+HEAD           := arch/arm/kernel/head-$(PROCESSOR).o \
+                  arch/arm/kernel/init_task.o
+SUBDIRS                := arch/arm/special $(SUBDIRS) arch/arm/lib arch/arm/kernel \
+                  arch/arm/mm arch/arm/nwfpe
 CORE_FILES     := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
 LIBS           := arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
-
-BLOCK_DRIVERS  := drivers/block/block.a
-CDROM_DRIVERS  := drivers/cdrom/cdrom.a
-ifeq ($(CONFIG_FB),y)
-CHAR_DRIVERS   := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
-else
-ifeq ($(CONFIG_VGA_CONSOLE),y)
-CHAR_DRIVERS   := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
-else
-CHAR_DRIVERS   := arch/arm/drivers/char/char.a
-endif
-endif
-MISC_DRIVERS   := drivers/misc/misc.a
-NET_DRIVERS    := drivers/net/net.a
-PARIDE_DRIVERS := drivers/block/paride/paride.a
-PCI_DRIVERS    := drivers/pci/pci.a
-SCSI_DRIVERS   := drivers/scsi/scsi.a
-SOUND_DRIVERS  := drivers/sound/sound.a
-VIDEO_DRIVERS  := drivers/video/video.a
-PNP_DRIVERS    := drivers/pnp/pnp.a
+DRIVERS                += arch/arm/special/special.a
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
-BLOCK_DRIVERS  += drivers/acorn/block/acorn-block.a
-CHAR_DRIVERS   += drivers/acorn/char/acorn-char.a
-NET_DRIVERS    += drivers/acorn/net/acorn-net.a drivers/net/net.a
-SCSI_DRIVERS   += drivers/acorn/scsi/acorn-scsi.a
+SUBDIRS                += drivers/acorn/block drivers/acorn/char drivers/acorn/net \
+                  drivers/acorn/scsi
+DRIVERS                += drivers/acorn/block/acorn-block.a \
+                  drivers/acorn/char/acorn-char.a \
+                  drivers/acorn/net/acorn-net.a \
+                  drivers/acorn/scsi/acorn-scsi.a
 endif
 
-DRIVERS                := $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS)
-
-ifeq ($(CONFIG_FB),y)
-DRIVERS                := $(DRIVERS) $(VIDEO_DRIVERS)
-else
-ifeq ($(CONFIG_VGA_CONSOLE),y)
-DRIVERS                := $(DRIVERS) $(VIDEO_DRIVERS)
-endif
-endif
-ifeq ($(CONFIG_SCSI),y)
-DRIVERS                := $(DRIVERS) $(SCSI_DRIVERS)
-endif
-ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),)
-DRIVERS                := $(DRIVERS) $(CDROM_DRIVERS)
-endif
-ifdef CONFIG_PCI
-DRIVERS                := $(DRIVERS) $(PCI_DRIVERS)
-endif
-ifeq ($(CONFIG_SOUND),y)
-DRIVERS                := $(DRIVERS) $(SOUND_DRIVERS)
-endif
-ifeq ($(CONFIG_PARIDE),y)
-DRIVERS                := $(DRIVERS) $(PARIDE_DRIVERS)
-endif
-ifdef CONFIG_PNP
-DRIVERS                := $(DRIVERS) $(PNP_DRIVERS)
+ifeq ($(CONFIG_NWFPE),y)
+DRIVERS                += arch/arm/nwfpe/math-emu.a
 endif
 
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
 symlinks::
        $(RM) include/asm-arm/arch include/asm-arm/proc
        (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc)
 
-# Once we've finished integrating the sources, the @$(MAKE) will disappear
-archmrproper:
-       rm -f include/asm-arm/arch include/asm-arm/proc
-       @$(MAKE) -C arch/$(ARCH)/drivers mrproper
-
 arch/arm/kernel: dummy
        $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel
 
@@ -231,19 +190,20 @@ arch/arm/mm: dummy
 arch/arm/lib: dummy
        $(MAKE) linuxsubdirs SUBDIRS=arch/arm/lib
 
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
-zImage: vmlinux
-       @$(MAKEBOOT) zImage
+zImage zinstall Image install: vmlinux
+       @$(MAKEBOOT) $@
 
-zinstall: vmlinux
-       @$(MAKEBOOT) zinstall
+# Once we've finished integrating the sources, the @$(MAKE) will disappear
+archmrproper:
+       rm -f include/asm-arm/arch include/asm-arm/proc
+       @$(MAKE) -C arch/$(ARCH)/special mrproper
 
-Image: vmlinux
-       @$(MAKEBOOT) Image
+archclean:
+       @$(MAKEBOOT) clean
+       $(RM) arch/arm/lib/constants.h
 
-install: vmlinux
-       @$(MAKEBOOT) install
+archdep:
+       @$(MAKEBOOT) dep
 
 # My testing targets (that short circuit a few dependencies)
 zImg:; @$(MAKEBOOT) zImage
@@ -251,10 +211,19 @@ Img:;     @$(MAKEBOOT) Image
 i:;    @$(MAKEBOOT) install
 zi:;   @$(MAKEBOOT) zinstall
 
-archclean:
-       @$(MAKEBOOT) clean
-       $(RM) arch/arm/lib/constants.h
+a5k_config:
+       $(RM) arch/arm/defconfig
+       cp arch/arm/def-configs/a5k arch/arm/defconfig
+
+ebsa110_config:
+       $(RM) arch/arm/defconfig
+       cp arch/arm/def-configs/ebsa110 arch/arm/defconfig
+
+footbridge_config:
+       $(RM) arch/arm/defconfig
+       cp arch/arm/def-configs/footbridge arch/arm/defconfig
+
+rpc_config:
+       $(RM) arch/arm/defconfig
+       cp arch/arm/def-configs/rpc arch/arm/defconfig
 
-archdep:
-       @$(MAKEBOOT) dep
-sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal
index 0c6a04c5b609d51f47afd83c239439440c5801e3..cf1481ab06cfa1022ca69584b04e4fa112f244f2 100644 (file)
@@ -11,10 +11,15 @@ HEAD        =$(COMPRESSED_HEAD)
 OBJS   =$(HEAD) misc.o $(COMPRESSED_EXTRA)
 CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC)
 ARFLAGS =rc
+FONTC  =$(TOPDIR)/drivers/video/font_acorn_8x8.c
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+OBJS   += ll_char_wr.o font.o
+endif
 
 all:           vmlinux
 
-vmlinux:       piggy.o $(OBJS)
+vmlinux:       $(OBJS) piggy.o
                $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o
 
 $(HEAD):       $(HEAD:.o=.S)
@@ -29,5 +34,8 @@ piggy.o:      $(SYSTEM)
                $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
                rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk;
 
+font.o:                $(FONTC)
+               $(CC) -Dstatic= -c -o $@ $(FONTC)
+
 clean:;                rm -f vmlinux core
 
diff --git a/arch/arm/boot/compressed/ll_char_wr.S b/arch/arm/boot/compressed/ll_char_wr.S
new file mode 100644 (file)
index 0000000..57865f2
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * linux/arch/arm/lib/ll_char_wr.S
+ *
+ * Copyright (C) 1995, 1996 Russell King.
+ *
+ * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
+ *
+ * 10-04-96    RMK     Various cleanups & reduced register usage.
+ * 08-04-98    RMK     Shifts re-ordered
+ */
+
+@ Regs: [] = corruptible
+@       {} = used
+@       () = do not use
+#define __ASSEMBLY__
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+               .text
+
+#define BOLD            0x01
+#define ITALIC          0x02
+#define UNDERLINE       0x04
+#define FLASH           0x08
+#define INVERSE         0x10
+
+LC0:           .word   SYMBOL_NAME(bytes_per_char_h)
+               .word   SYMBOL_NAME(video_size_row)
+               .word   SYMBOL_NAME(acorndata_8x8)
+               .word   SYMBOL_NAME(con_charconvtable)
+
+ENTRY(ll_write_char)
+               stmfd   sp!, {r4 - r7, lr}
+@
+@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
+@
+               eor     ip, r1, #UNDERLINE << 9
+/*
+ * calculate colours
+ */
+               tst     r1, #INVERSE << 9
+               moveq   r2, r1, lsr #16
+               moveq   r3, r1, lsr #24
+               movne   r2, r1, lsr #24
+               movne   r3, r1, lsr #16
+               and     r3, r3, #255
+               and     r2, r2, #255
+/*
+ * calculate offset into character table
+ */
+               mov     r1, r1, lsl #23
+               mov     r1, r1, lsr #20
+/*
+ * calculate offset required for each row [maybe I should make this an argument to this fn.
+ * Have to see what the register usage is like in the calling routines.
+ */
+               adr     r4, LC0
+               ldmia   r4, {r4, r5, r6, lr}
+               ldr     r4, [r4]
+               ldr     r5, [r5]
+/*
+ * Go to resolution-dependent routine...
+ */
+               cmp     r4, #4
+               blt     Lrow1bpp
+               eor     r2, r3, r2                      @ Create eor mask to change colour from bg
+               orr     r3, r3, r3, lsl #8              @ to fg.
+               orr     r3, r3, r3, lsl #16
+               add     r0, r0, r5, lsl #3              @ Move to bottom of character
+               add     r1, r1, #7
+               ldrb    r7, [r6, r1]
+               tst     ip, #UNDERLINE << 9
+               eoreq   r7, r7, #255
+               teq     r4, #8
+               beq     Lrow8bpplp
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
+@
+               orr     r3, r3, r3, lsl #4
+Lrow4bpplp:    ldr     r7, [lr, r7, lsl #2]
+               mul     r7, r2, r7
+               tst     r1, #7                          @ avoid using r7 directly after
+               eor     ip, r3, r7
+               str     ip, [r0, -r5]!
+               LOADREGS(eqfd, sp!, {r4 - r7, pc})
+               sub     r1, r1, #1
+               ldrb    r7, [r6, r1]
+               ldr     r7, [lr, r7, lsl #2]
+               mul     r7, r2, r7
+               tst     r1, #7                          @ avoid using r7 directly after
+               eor     ip, r3, r7
+               str     ip, [r0, -r5]!
+               subne   r1, r1, #1
+               ldrneb  r7, [r6, r1]
+               bne     Lrow4bpplp
+               LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
+@
+Lrow8bpplp:    mov     ip, r7, lsr #4
+               ldr     ip, [lr, ip, lsl #2]
+               mul     r4, r2, ip
+               and     ip, r7, #15                     @ avoid r4
+               ldr     ip, [lr, ip, lsl #2]            @ avoid r4
+               mul     ip, r2, ip                      @ avoid r4
+               eor     r4, r3, r4                      @ avoid ip
+               tst     r1, #7                          @ avoid ip
+               sub     r0, r0, r5                      @ avoid ip
+               eor     ip, r3, ip
+               stmia   r0, {r4, ip}
+               LOADREGS(eqfd, sp!, {r4 - r7, pc})
+               sub     r1, r1, #1
+               ldrb    r7, [r6, r1]
+               mov     ip, r7, lsr #4
+               ldr     ip, [lr, ip, lsl #2]
+               mul     r4, r2, ip
+               and     ip, r7, #15                     @ avoid r4
+               ldr     ip, [lr, ip, lsl #2]            @ avoid r4
+               mul     ip, r2, ip                      @ avoid r4
+               eor     r4, r3, r4                      @ avoid ip
+               tst     r1, #7                          @ avoid ip
+               sub     r0, r0, r5                      @ avoid ip
+               eor     ip, r3, ip
+               stmia   r0, {r4, ip}
+               subne   r1, r1, #1
+               ldrneb  r7, [r6, r1]
+               bne     Lrow8bpplp
+               LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@
+@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc)
+@
+Lrow1bpp:      add     r6, r6, r1
+               ldmia   r6, {r4, r7}
+               tst     ip, #INVERSE << 9
+               mvnne   r4, r4
+               mvnne   r7, r7
+               strb    r4, [r0], r5
+               mov     r4, r4, lsr #8
+               strb    r4, [r0], r5
+               mov     r4, r4, lsr #8
+               strb    r4, [r0], r5
+               mov     r4, r4, lsr #8
+               strb    r4, [r0], r5
+               strb    r7, [r0], r5
+               mov     r7, r7, lsr #8
+               strb    r7, [r0], r5
+               mov     r7, r7, lsr #8
+               strb    r7, [r0], r5
+               mov     r7, r7, lsr #8
+               tst     ip, #UNDERLINE << 9
+               mvneq   r7, r7
+               strb    r7, [r0], r5
+               LOADREGS(fd, sp!, {r4 - r7, pc})
+
+               .bss
+ENTRY(con_charconvtable)
+               .space  1024
index 467218db714ed13d12f2bbafaa051d9216c7b018..2fea6a6614effeb7fd137819c659f5dc7df0bf08 100644 (file)
@@ -14,18 +14,31 @@ choice 'ARM system type'    \
         A5000                  CONFIG_ARCH_A5K \
         RiscPC                 CONFIG_ARCH_RPC \
         EBSA-110               CONFIG_ARCH_EBSA110 \
-        EBSA-285               CONFIG_ARCH_EBSA285 \
-        NexusPCI               CONFIG_ARCH_NEXUSPCI \
-        Corel-VNC              CONFIG_ARCH_VNC \
-        Tbox                   CONFIG_ARCH_TBOX" RiscPC
+        FootBridge-based       CONFIG_FOOTBRIDGE" RiscPC
+
+if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+  bool 'FootBridge in HOST mode'       CONFIG_HOST_FOOTBRIDGE
+  if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
+    define_bool CONFIG_ADDIN_FOOTBRIDGE n
+  else
+    define_bool CONFIG_ADDIN_FOOTBRIDGE y
+  fi
+fi
+
+if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
+  bool '  Include support for Intel EBSA285' CONFIG_ARCH_EBSA285
+  bool '  Include support for Chalice CATS boards' CONFIG_CATS
+  bool '  Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER
+fi
 
-if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
-  bool '  Include support for CATS boards' CONFIG_CATS
+if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then
+  # If we get any other footbridge-based plug-in boards, then
+  # add your architecture options here
+  define_bool CONFIG_ARCH_CO285 y
 fi
 
 # Select various configuration options depending on the machine type
 #  Easy check for Acorn-style architectures
-
 if [ "$CONFIG_ARCH_ARC" = "y" -o \
      "$CONFIG_ARCH_A5K" = "y" -o \
      "$CONFIG_ARCH_RPC" = "y" ]; then
@@ -34,23 +47,19 @@ else
   define_bool CONFIG_ARCH_ACORN n
 fi
 
-if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
-  define_bool CONFIG_BUS_I2C y
-fi
+#if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
+#  define_bool CONFIG_BUS_I2C y
+#fi
 
 #  These machines always have PCI
-
 if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
-     "$CONFIG_ARCH_VNC" = "y" ]; then
+     "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
   define_bool CONFIG_PCI y
 fi
-if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
-  bool "PCI support" CONFIG_PCI
-fi
 
 # These machines have ISA-DMA
 if [ "$CONFIG_CATS" = "y" -o \
-     "$CONFIG_ARCH_VNC" = "y" ]; then
+     "$CONFIG_ARCH_NETWINDER" = "y" ]; then
   define_bool CONFIG_ISA_DMA y
 else
   define_bool CONFIG_ISA_DMA n
@@ -59,7 +68,6 @@ fi
 # Figure out whether this system uses 26-bit or 32-bit CPUs.  Nobody has
 # ever built a machine that can take both, and now that ARM3 is obsolete
 # nobody is likely to either.
-
 if [ "$CONFIG_ARCH_ARC" = "y" -o \
      "$CONFIG_ARCH_A5K" = "y" ]; then
   define_bool CONFIG_CPU_32 n
@@ -71,7 +79,6 @@ fi
 
 # Now allow the user to choose a more precise CPU.  This is only used to set
 # the flags we pass to GCC, not in any code.
-
 choice 'Optimise for CPU'                              \
        "ARM2           CONFIG_CPU_ARM2 \
         ARM3           CONFIG_CPU_ARM3 \
@@ -80,22 +87,21 @@ choice 'Optimise for CPU'                           \
         SA110          CONFIG_CPU_SA110" ARM6
 
 if [ "$CONFIG_CPU_26" = "y" ]; then
-
 # For 26-bit CPUs, the page size changes with the amount of physical RAM!
 # The default is 4MB but if the user has less they have to own up to it here.
-
   choice 'Physical memory size'                \
        "4MB+           CONFIG_PAGESIZE_32      \
-        2MB            CONFIG_PAGESIZE_16      \
-        1MB/512K       CONFIG_PAGESIZE_8" 4MB+
+        2MB            CONFIG_PAGESIZE_16" 4MB+
 fi
 endmenu
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW
-bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
+if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
+  bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP
+fi
+bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS
 endmenu
 
 mainmenu_option next_comment
@@ -113,13 +119,19 @@ bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Math emulation' CONFIG_NWFPE
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+if [ "$CONFIG_CPU_32" = "y" ]; then
+  tristate 'RISC OS personality' CONFIG_ARTHUR
+fi
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  if [ "$CONFIG_ARCH_ARC" = "y" ]; then
+    dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  fi
   dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
 # If exactly one hardware type is selected then parport will optimise away
 # support for loading any others.  Defeat this if the user is keen.
@@ -129,13 +141,29 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
     fi
   fi
 fi
-if [ "$CONFIG_ARCH_EBSA285" = "y" -o \
-     "$CONFIG_ARCH_EBSA110" = "y" -o \
-     "$CONFIG_ARCH_VNC" = "y" ]; then
+if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
+     "$CONFIG_ARCH_NETWINDER" = "y" -o \
+     "$CONFIG_CATS" = "y" ]; then
   string 'Initial kernel command string' CONFIG_CMDLINE
 fi
+if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+     "$CONFIG_ARCH_EBSA110" = "y" -o   \
+     "$CONFIG_ARCH_EBSA285" = "y" -o   \
+     "$CONFIG_ARCH_CO285" = "y" ]; then
+  bool 'Timer and CPU usage LEDs' CONFIG_LEDS
+  if [ "$CONFIG_LEDS" = "y" ]; then
+    if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+         "$CONFIG_ARCH_EBSA285" = "y" -o   \
+        "$CONFIG_ARCH_CO285" = "y" ]; then
+      bool '  Timer LED' CONFIG_LEDS_TIMER
+      bool '  CPU usage LED' CONFIG_LEDS_CPU
+    fi
+  fi
+fi
 endmenu
 
+source drivers/i2o/Config.in
+
 source drivers/pnp/Config.in
 
 source drivers/block/Config.in
@@ -144,15 +172,19 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
   source drivers/acorn/block/Config.in
 fi
 
-if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then
-  source arch/arm/drivers/char/Config.in
-else
-  source drivers/char/Config.in
-fi
+source drivers/char/Config.in
 if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-  source drivers/acorn/char/Config.in
+  if [ "$CONFIG_MOUSE" = "y" ]; then
+    if [ "$CONFIG_ARCH_RPC" != "y" ]; then
+      define_bool CONFIG_KBDMOUSE y
+    else
+      define_bool CONFIG_RPCMOUSE y
+    fi
+  fi
 fi
 
+source drivers/usb/Config.in
+
 if [ "$CONFIG_VT" = "y" ]; then
   mainmenu_option next_comment
   comment 'Console drivers'
@@ -166,9 +198,11 @@ fi
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
-fi
 
-if [ "$CONFIG_NET" = "y" ]; then
+  source net/ax25/Config.in
+
+  source net/irda/Config.in
+
   mainmenu_option next_comment
   comment 'Network device support'
 
@@ -179,6 +213,15 @@ if [ "$CONFIG_NET" = "y" ]; then
   endmenu
 fi
 
+# mainmenu_option next_comment
+# comment 'ISDN subsystem'
+#
+# tristate 'ISDN support' CONFIG_ISDN
+# if [ "$CONFIG_ISDN" != "n" ]; then
+#   source drivers/isdn/Config.in
+# fi
+# endmenu
+
 mainmenu_option next_comment
 comment 'SCSI support'
 
@@ -200,21 +243,29 @@ if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then
   endmenu
 fi
 
-# mainmenu_option next_comment
-# comment 'ISDN subsystem'
-#
-# tristate 'ISDN support' CONFIG_ISDN
-# if [ "$CONFIG_ISDN" != "n" ]; then
-#   source drivers/isdn/Config.in
-# fi
-# endmenu
-
 source fs/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS
+bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
+bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS
+bool 'Verbose user fault messages' CONFIG_DEBUG_USER
+bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  if [ "$CONFIG_CPU_26" = "y" ]; then
+    bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE
+  fi
+
+  # These options are only for real kernel hackers
+  # who want to get their hands dirty. 
+  bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
+  if [ "$CONFIG_DEBUG_LL" = "y" ]; then
+    if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+      bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT
+    fi
+  fi
+fi
 endmenu
index db89599be80c5b751f674f1669439f985b973b47..ce85d6ffc469e1c4fe9238d452d11f8f038430a7 100644 (file)
@@ -3,48 +3,72 @@
 #
 CONFIG_ARM=y
 
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+CONFIG_FOOTBRIDGE=y
+CONFIG_HOST_FOOTBRIDGE=y
+# CONFIG_ADDIN_FOOTBRIDGE is not set
+CONFIG_ARCH_EBSA285=y
+# CONFIG_CATS is not set
+CONFIG_ARCH_NETWINDER=y
+# CONFIG_ARCH_ACORN is not set
+CONFIG_PCI=y
+CONFIG_ISA_DMA=y
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 
 #
 # General setup
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
-CONFIG_ARCH_RPC=y
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_NEXUSPCI is not set
-CONFIG_ARCH_ACORN=y
-# CONFIG_PCI is not set
-# CONFIG_CPU_ARM2 is not set
-# CONFIG_CPU_ARM3 is not set
-# CONFIG_CPU_ARM6 is not set
-CONFIG_CPU_SA110=y
-CONFIG_FRAME_POINTER=y
-# CONFIG_BINUTILS_NEW is not set
-CONFIG_DEBUG_ERRORS=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_NWFPE=y
 CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=m
-# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
+CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
 
 #
-# Floppy, IDE, and other block devices
+# Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -52,32 +76,165 @@ CONFIG_BLK_DEV_IDE=y
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_IDE_PCMCIA is not set
-CONFIG_BLK_DEV_IDE_CARDS=y
-CONFIG_BLK_DEV_IDE_ICSIDE=y
-# CONFIG_BLK_DEV_IDE_RAPIDE is not set
-# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_BLK_DEV_OFFBOARD=y
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_CMD646 is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
 CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
+CONFIG_MD_MIRRORING=m
+CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
 CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-CONFIG_BLK_DEV_PART=y
+CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
 # CONFIG_BLK_DEV_HD is not set
 
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+CONFIG_WATCHDOG=y
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WDT is not set
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+CONFIG_NWFLASH=m
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_FILTER is not set
@@ -85,21 +242,20 @@ CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+CONFIG_IP_ALIAS=y
 # CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
 #
 # CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
-# CONFIG_SKB_LARGE is not set
+CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 
 #
@@ -111,107 +267,198 @@ CONFIG_IP_NOSR=y
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
+# CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_PROFILE is not set
 
 #
-# SCSI support
+# Amateur Radio support
 #
-CONFIG_SCSI=y
+# CONFIG_HAMRADIO is not set
 
 #
-# SCSI support type (disk, tape, CD-ROM)
+# IrDA subsystem support
 #
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-CONFIG_BLK_DEV_SR=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
+# CONFIG_IRDA is not set
 
 #
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+# Network device support
 #
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=y
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DE4X5 is not set
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_ES3210 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
 
 #
-# SCSI low-level drivers
+# CCP compressors for PPP are only built as modules.
 #
-CONFIG_SCSI_ACORNSCSI_3=m
-CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
-CONFIG_SCSI_ACORNSCSI_SYNC=y
-CONFIG_SCSI_CUMANA_2=m
-CONFIG_SCSI_POWERTECSCSI=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
 
 #
-# The following drives are not fully supported
+# SCSI support
 #
-CONFIG_SCSI_CUMANA_1=m
-CONFIG_SCSI_OAK1=m
-CONFIG_SCSI_PPA=m
-CONFIG_SCSI_PPA_HAVE_PEDANTIC=2
+# CONFIG_SCSI is not set
 
 #
-# Network device support
+# Sound
 #
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_PPP=m
+CONFIG_SOUND=m
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_PAS is not set
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_ADLIB=m
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_VIDC is not set
+CONFIG_SOUND_WAVEARTIST=m
+CONFIG_WAVEARTIST_BASE=250
+CONFIG_WAVEARTIST_IRQ=12
+CONFIG_WAVEARTIST_DMA=3
+CONFIG_WAVEARTIST_DMA2=7
 
 #
-# CCP compressors for PPP are only built as modules.
+# Additional low level sound drivers
 #
-# CONFIG_SLIP is not set
-CONFIG_ETHER1=m
-CONFIG_ETHER3=m
-CONFIG_ETHERH=m
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_ADFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-CONFIG_NFSD=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_ADFS_FS=y
-CONFIG_ADFS_FS=y
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_ICS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX is not set
 CONFIG_NLS=y
 
 #
 # Native Language Support
 #
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
 # CONFIG_NLS_CODEPAGE_860 is not set
@@ -223,8 +470,8 @@ CONFIG_NLS=y
 # CONFIG_NLS_CODEPAGE_866 is not set
 # CONFIG_NLS_CODEPAGE_869 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
 # CONFIG_NLS_ISO8859_5 is not set
@@ -232,34 +479,15 @@ CONFIG_NLS=y
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-CONFIG_ATOMWIDE_SERIAL=y
-CONFIG_DUALSP_SERIAL=y
-CONFIG_MOUSE=y
-CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
-# CONFIG_UMISC is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_RPCMOUSE=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-CONFIG_VIDC=y
-CONFIG_AUDIO=y
-DSP_BUFFSIZE=65536
-
 #
 # Kernel hacking
 #
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_LL is not set
index 23b2c12671ecafa36e886e732517010cdc67ef67..5bcc22af1e4329beb583e50baebace9f12e1eaad 100644 (file)
@@ -9,31 +9,37 @@ HEAD_OBJ  = head-$(PROCESSOR).o
 ENTRY_OBJ = entry-$(PROCESSOR).o
 
 O_TARGET := kernel.o
-O_OBJS   := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \
+O_OBJS   := $(ENTRY_OBJ) irq.o process.o ptrace.o setup.o \
            signal.o sys_arm.o time.o traps.o
 
-DMA_OBJS_arc      = dma-arc.o
-DMA_OBJS_a5k      = dma-a5k.o
-DMA_OBJS_rpc      = dma-rpc.o
-DMA_OBJS_ebsa110  = dma-dummy.o
-DMA_OBJS_ebsa285  = dma-ebsa285.o
-DMA_OBJS_nexuspci =
-DMA_OBJS_vnc      = dma-vnc.o
-
-O_OBJS_arc        = ecard.o iic.o fiq.o oldlatches.o
-O_OBJS_a5k        = ecard.o iic.o fiq.o
-O_OBJS_rpc        = ecard.o iic.o fiq.o
-O_OBJS_ebsa110    = leds-ebsa110.o
-O_OBJS_ebsa285    = leds-ebsa285.o hw-ebsa285.o
-O_OBJS_nexuspci   =
-O_OBJS_vnc        = leds-ebsa285.o hw-vnc.o
+ifeq ($(CONFIG_ISA_DMA),y)
+  ISA_DMA_OBJS += dma-isa.o
+endif
+
+O_OBJS_arc        = dma-arc.o iic.o fiq.o oldlatches.o
+O_OBJS_a5k        = dma-a5k.o iic.o fiq.o
+O_OBJS_rpc        = dma-rpc.o iic.o fiq.o
+O_OBJS_ebsa110    = dma-dummy.o
+O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS)
+O_OBJS_nexuspci   = dma-dummy.o
+
+OX_OBJS_arc      = dma.o
+OX_OBJS_a5k      = dma.o
+OX_OBJS_rpc      = dma.o
+OX_OBJS_ebsa110          = 
+OX_OBJS_footbridge= dma.o hw-footbridge.o
+OX_OBJS_nexuspci  =
 
 all: lib kernel.o $(HEAD_OBJ) init_task.o
 
+O_OBJS += $(O_OBJS_$(MACHINE))
+
 ifeq ($(CONFIG_MODULES),y)
   OX_OBJS = armksyms.o
-else
-  O_OBJS += armksyms.o
+endif
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+  OX_OBJS += ecard.o
 endif
 
 ifeq ($(MACHINE),nexuspci)
@@ -46,17 +52,23 @@ else
   endif
 endif
 
-ifneq ($(DMA_OBJS_$(MACHINE)),)
-  OX_OBJS += dma.o
-  O_OBJS  += $(DMA_OBJS_$(MACHINE))
-  ifeq ($(CONFIG_ISA_DMA),y)
-    O_OBJS += dma-isa.o
-  endif
+ifdef CONFIG_LEDS
+  OX_OBJS += leds-$(MACHINE).o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+  OX_OBJS += $(OX_OBJS_$(MACHINE))
 else
-  O_OBJS += dma-dummy.o
+  O_OBJS += $(OX_OBJS_$(MACHINE))
 endif
 
-O_OBJS += $(O_OBJS_$(MACHINE))
+ifeq ($(CONFIG_ARTHUR),y)
+  O_OBJS += arthur.o
+else
+  ifeq ($(CONFIG_ARTHUR),m)
+    M_OBJS += arthur.o
+  endif
+endif
 
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
        $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
@@ -72,3 +84,7 @@ $(ENTRY_OBJ): ../lib/constants.h
 
 lib:
        $(MAKE) -C ../lib constants.h
+
+# Spell out some dependencies that `make dep' doesn't spot
+entry-armv.o: calls.S
+entry-armo.o: calls.S
index 149349b4a0d741ca90279516d604f8f09853ab61..c93421ba7763bd6556f0dfe48551fe052022a019 100644 (file)
@@ -6,20 +6,40 @@
 #include <linux/mman.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/in6.h>
 
-#include <asm/ecard.h>
 #include <asm/elf.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#include <asm/semaphore.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
 extern void inswb(unsigned int port, void *to, int len);
 extern void outswb(unsigned int port, const void *to, int len);
 
+extern unsigned int local_bh_count[NR_CPUS];
+extern unsigned int local_irq_count[NR_CPUS];
+
+extern void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
+extern void iounmap(void *addr);
+
+extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/*
+ * syscalls
+ */
+extern int sys_write(int, const char *, int);
+extern int sys_read(int, char *, int);
+extern int sys_lseek(int, off_t, int);
+extern int sys_open(const char *, int, int);
+extern int sys_exit(int);
+extern int sys_wait4(int, int *, int, struct rusage *);
+
 /*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
@@ -43,6 +63,8 @@ extern void __udivsi3(void);
 extern void __umoddi3(void);
 extern void __umodsi3(void);
 
+extern void ret_from_exception(void);
+extern void fpundefinstr(void);
 extern void fp_enter(void);
 #define EXPORT_SYMBOL_ALIAS(sym,orig) \
  const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \
@@ -57,32 +79,46 @@ EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
 EXPORT_SYMBOL_ALIAS(fp_printk,printk);
 EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
 
+#ifdef CONFIG_CPU_26
+EXPORT_SYMBOL(fpundefinstr);
+EXPORT_SYMBOL(ret_from_exception);
+#endif
+
        /* platform dependent support */
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(xchg_str);
-
-       /* expansion card support */
-#ifdef CONFIG_ARCH_ACORN
-EXPORT_SYMBOL(ecard_startfind);
-EXPORT_SYMBOL(ecard_find);
-EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_address);
+EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(local_irq_count);
+#ifdef CONFIG_CPU_32
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
 #endif
+EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 
        /* processor dependencies */
 EXPORT_SYMBOL(processor);
-EXPORT_SYMBOL(machine_type);
+EXPORT_SYMBOL(__machine_arch_type);
+
+       /* networking */
+EXPORT_SYMBOL(csum_partial_copy);
+EXPORT_SYMBOL(__csum_ipv6_magic);
 
        /* io */
-EXPORT_SYMBOL(outswb);
+EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
-EXPORT_SYMBOL(inswb);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+
+EXPORT_SYMBOL(_memcpy_fromio);
+EXPORT_SYMBOL(_memcpy_toio);
+EXPORT_SYMBOL(_memset_io);
 
        /* address translation */
 #ifndef __virt_to_phys__is_a_macro
@@ -98,7 +134,9 @@ EXPORT_SYMBOL(__virt_to_bus);
 EXPORT_SYMBOL(__bus_to_virt);
 #endif
 
+#ifndef CONFIG_NO_PGT_CACHE
 EXPORT_SYMBOL(quicklists);
+#endif
 EXPORT_SYMBOL(__bad_pmd);
 EXPORT_SYMBOL(__bad_pmd_kernel);
 
@@ -167,3 +205,17 @@ EXPORT_SYMBOL(find_next_zero_bit);
 EXPORT_SYMBOL(armidlist);
 EXPORT_SYMBOL(armidindex);
 EXPORT_SYMBOL(elf_platform);
+
+       /* syscalls */
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_wait4);
+
+       /* semaphores */
+EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_interruptible_failed);
+EXPORT_SYMBOL_NOVERS(__up_wakeup);
+
diff --git a/arch/arm/kernel/arthur.c b/arch/arm/kernel/arthur.c
new file mode 100644 (file)
index 0000000..9994fdd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Arthur personality
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#include <linux/personality.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <asm/ptrace.h>
+
+/* RISC OS doesn't have many signals, and a lot of those that it does
+   have don't map easily to any Linux equivalent.  Never mind.  */
+
+#define RISCOS_SIGABRT         1
+#define RISCOS_SIGFPE          2
+#define RISCOS_SIGILL          3
+#define RISCOS_SIGINT          4
+#define RISCOS_SIGSEGV         5
+#define RISCOS_SIGTERM         6
+#define RISCOS_SIGSTAK         7
+#define RISCOS_SIGUSR1         8
+#define RISCOS_SIGUSR2         9
+#define RISCOS_SIGOSERROR      10
+
+static unsigned long riscos_to_linux_signals[32] = {
+       0,      1,      2,      3,      4,      5,      6,      7,
+       8,      9,      10,     11,     12,     13,     14,     15,
+       16,     17,     18,     19,     20,     21,     22,     23,
+       24,     25,     26,     27,     28,     29,     30,     31
+};
+
+static unsigned long linux_to_riscos_signals[32] = {
+       0,              -1,             RISCOS_SIGINT,  -1,
+               RISCOS_SIGILL,  5,              RISCOS_SIGABRT, 7,
+       RISCOS_SIGFPE,  9,              RISCOS_SIGUSR1, RISCOS_SIGSEGV, 
+       RISCOS_SIGUSR2, 13,             14,             RISCOS_SIGTERM,
+       16,             17,             18,             19,
+       20,             21,             22,             23,
+       24,             25,             26,             27,
+       28,             29,             30,             31
+};
+
+static void arthur_lcall7(int nr, struct pt_regs *regs)
+{
+       struct siginfo info;
+       info.si_signo = SIGSWI;
+       info.si_code = nr;
+       /* Bounce it to the emulator */
+       send_sig_info(SIGSWI, &info, current);
+}
+
+static struct exec_domain riscos_exec_domain = {
+       "Arthur",       /* name */
+       (lcall7_func)arthur_lcall7,
+       PER_RISCOS, PER_RISCOS,
+       riscos_to_linux_signals,
+       linux_to_riscos_signals,
+#ifdef MODULE
+       &__this_module, /* No usage counter. */
+#else
+       NULL,
+#endif
+       NULL            /* Nothing after this in the list. */
+};
+
+/*
+ * We could do with some locking to stop Arthur being removed while
+ * processes are using it.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int initialise_arthur(void)
+#endif
+{
+       return register_exec_domain(&riscos_exec_domain);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       unregister_exec_domain(&riscos_exec_domain);
+}
+#endif
index 46f71fa927f623f5e6c0ad81701d78030b6ba216..154e3aeabe1538545df47772defec41b10179281 100644 (file)
@@ -31,7 +31,7 @@
                .long   SYMBOL_NAME(sys_lseek)
 /* 20 */       .long   SYMBOL_NAME(sys_getpid)
                .long   SYMBOL_NAME(sys_mount_wrapper)
-               .long   SYMBOL_NAME(sys_umount)
+               .long   SYMBOL_NAME(sys_oldumount)
                .long   SYMBOL_NAME(sys_setuid)
                .long   SYMBOL_NAME(sys_getuid)
 /* 25 */       .long   SYMBOL_NAME(sys_stime)
@@ -61,7 +61,7 @@
                .long   SYMBOL_NAME(sys_geteuid)
 /* 50 */       .long   SYMBOL_NAME(sys_getegid)
                .long   SYMBOL_NAME(sys_acct)
-               .long   SYMBOL_NAME(sys_ni_syscall)             /* was sys_phys */
+               .long   SYMBOL_NAME(sys_umount)
                .long   SYMBOL_NAME(sys_ni_syscall)             /* was sys_lock */
                .long   SYMBOL_NAME(sys_ioctl)
 /* 55 */       .long   SYMBOL_NAME(sys_fcntl)
                .long   SYMBOL_NAME(sys_ni_syscall)             /* was sys_profil */
                .long   SYMBOL_NAME(sys_statfs)
 /* 100 */      .long   SYMBOL_NAME(sys_fstatfs)
-               .long   SYMBOL_NAME(sys_ni_syscall)             /* .long        _sys_ioperm */
+               .long   SYMBOL_NAME(sys_ni_syscall)
                .long   SYMBOL_NAME(sys_socketcall)
                .long   SYMBOL_NAME(sys_syslog)
                .long   SYMBOL_NAME(sys_setitimer)
                .long   SYMBOL_NAME(sys_newlstat)
                .long   SYMBOL_NAME(sys_newfstat)
                .long   SYMBOL_NAME(sys_uname)
-/* 110 */      .long   SYMBOL_NAME(sys_iopl)
+/* 110 */      .long   SYMBOL_NAME(sys_ni_syscall)
                .long   SYMBOL_NAME(sys_vhangup)
                .long   SYMBOL_NAME(sys_idle)
                .long   SYMBOL_NAME(sys_syscall)                /* call a syscall */
                .long   SYMBOL_NAME(sys_capget)
 /* 185 */      .long   SYMBOL_NAME(sys_capset)
                .long   SYMBOL_NAME(sys_sigaltstack_wrapper)
+               .long   SYMBOL_NAME(sys_sendfile)
+               .long   SYMBOL_NAME(sys_ni_syscall)
+               .long   SYMBOL_NAME(sys_ni_syscall)
+/* 190 */      .long   SYMBOL_NAME(sys_vfork_wrapper)
 
                .rept   NR_syscalls-186
                        .long   SYMBOL_NAME(sys_ni_syscall)
index aa66ee04a534bfab3fd51d414c0f6298ef1292b8..c4103abee3b145c30ec7e155e0fe540ef35190cc 100644 (file)
@@ -8,17 +8,17 @@
 #include <linux/pci.h>
 #include <linux/ptrace.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
 #include <linux/init.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
+#include <asm/hardware.h>
 
-#define MAX_SLOTS              20
+#define MAX_SLOTS              21
 
 extern void pcibios_fixup_ebsa285(struct pci_dev *dev);
 extern void pcibios_init_ebsa285(void);
-extern void pcibios_fixup_vnc(struct pci_dev *dev);
-extern void pcibios_init_vnc(void);
 
 int
 pcibios_present(void)
@@ -33,11 +33,12 @@ pcibios_base_address(unsigned char bus, unsigned char dev_fn)
                int slot = PCI_SLOT(dev_fn);
                
                if (slot < MAX_SLOTS)
-                       return 0xf8c00000 + (slot << 11) + (PCI_FUNC(dev_fn) << 8);
+                       return PCICFG0_BASE + 0xc00000 +
+                               (slot << 11) + (PCI_FUNC(dev_fn) << 8);
                else
                        return 0;
        } else
-               return 0xf9000000 | (bus << 16) | (dev_fn << 8);
+               return PCICFG1_BASE | (bus << 16) | (dev_fn << 8);
 }
 
 int
@@ -151,10 +152,7 @@ __initfunc(void pcibios_fixup(void))
        struct pci_dev *dev;
 
        for (dev = pci_devices; dev; dev = dev->next) {
-               if (machine_is_ebsa285() || machine_is_cats())
-                       pcibios_fixup_ebsa285(dev);
-               if (machine_is_netwinder())
-                       pcibios_fixup_vnc(dev);
+               pcibios_fixup_ebsa285(dev);
 
                pcibios_write_config_byte(dev->bus->number, dev->devfn,
                                          PCI_INTERRUPT_LINE, dev->irq);
@@ -164,18 +162,83 @@ __initfunc(void pcibios_fixup(void))
                        dev->bus->number, dev->devfn,
                        dev->vendor, dev->device, dev->irq);
        }
-       if (machine_is_netwinder())
-               hw_init();
+
+       hw_init();
 }
 
 __initfunc(void pcibios_init(void))
 {
-       if (machine_is_ebsa285() || machine_is_cats())
-               pcibios_init_ebsa285();
-       if (machine_is_netwinder())
-               pcibios_init_vnc();
-
-       printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008);
+       unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+       unsigned long cntl;
+
+       *CSR_SDRAMBASEMASK    = (mem_size - 1) & 0x0ffc0000;
+       *CSR_SDRAMBASEOFFSET  = 0;
+       *CSR_ROMBASEMASK      = 0x80000000;
+       *CSR_CSRBASEMASK      = 0;
+       *CSR_CSRBASEOFFSET    = 0;
+       *CSR_PCIADDR_EXTN     = 0;
+
+#ifdef CONFIG_HOST_FOOTBRIDGE
+       /*
+        * Against my better judgement, Philip Blundell still seems
+        * to be saying that we should initialise the PCI stuff here
+        * when the PCI_CFN bit is not set, dispite my comment below,
+        * which he decided to remove.  If it is not set, then
+        * the card is in add-in mode, and we're in a machine where
+        * the bus is set up by 'others'.
+        *
+        * We should therefore not mess about with the mapping in
+        * anyway, and we should not be using the virt_to_bus functions
+        * that exist in the HOST architecture mode (since they assume
+        * a fixed mapping).
+        *
+        * Instead, you should be using ADDIN mode, which allows for
+        * this situation.  This does assume that you have correctly
+        * initialised the PCI bus, which you must have done to get
+        * your PC booted.
+        *
+        * Unfortunately, he seems to be blind to this.  I guess he'll
+        * also remove all this.
+        *
+        * And THIS COMMENT STAYS, even if this gets patched, thank
+        * you.
+        */
+
+       /*
+        * Map our SDRAM at a known address in PCI space, just in case
+        * the firmware had other ideas.  Using a nonzero base is
+        * necessary, since some VGA cards forcefully use PCI addresses
+        * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
+        *
+        * NOTE! If you need to chec the PCI_CFN bit in the SA110
+        * control register then you've configured the kernel wrong.
+        * If you're not using host mode, then DO NOT set
+        * CONFIG_HOST_FOOTBRIDGE, but use CONFIG_ADDIN_FOOTBRIDGE
+        * instead.  In this case, you MUST supply some firmware
+        * to allow your PC to boot, plus we should not modify the
+        * mappings that the PC BIOS has set up for us.
+        */
+       *CSR_PCICACHELINESIZE = 0x00002008;
+       *CSR_PCICSRBASE       = 0;
+       *CSR_PCICSRIOBASE     = 0;
+       *CSR_PCISDRAMBASE     = virt_to_bus((void *)PAGE_OFFSET);
+       *CSR_PCIROMBASE       = 0;
+       *CSR_PCICMD           = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                               PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
+                               PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
+                               (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
+#endif
+
+       /*
+        * Clear any existing errors - we aren't
+        * interested in historical data...
+        */
+       cntl = *CSR_SA110_CNTL & 0xffffde07;
+       *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
+
+       pcibios_init_ebsa285();
+
+       printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff);
 }
 
 __initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
index 18bbf0c9c45a563d612555d9590dcd5489afa63a..df02ea54e4d3e5cf3fec1ec6e31ed0b01261185e 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/fiq.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
-#include <asm/pgtable.h>
 
 #include "dma.h"
 
@@ -37,8 +36,9 @@ int arch_get_dma_residue(dmach_t channel, dma_t *dma)
        if (channel != DMA_VIRTUAL_FLOPPY)
                printk("arch_dma_count: invalid channel %d\n", channel);
        else {
-               extern int floppy_fiqresidual(void);
-               return floppy_fiqresidual();
+               struct pt_regs regs;
+               get_fiq_regs(&regs);
+               return regs.ARM_r9;
        }
        return 0;
 }
@@ -48,6 +48,7 @@ void arch_enable_dma(dmach_t channel, dma_t *dma)
        if (channel != DMA_VIRTUAL_FLOPPY)
                printk("arch_enable_dma: invalid channel %d\n", channel);
        else {
+               struct pt_regs regs;
                void *fiqhandler_start;
                unsigned int fiqhandler_length;
                extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
@@ -67,8 +68,10 @@ void arch_enable_dma(dmach_t channel, dma_t *dma)
                        return;
                }
                memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
-               flush_page_to_ram(0);
-               floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+               regs.ARM_r9 = dma->buf.length;
+               regs.ARM_r10 = __bus_to_virt(dma->buf.address);
+               regs.ARM_fp = (int)PCIO_FLOPPYDMABASE;
+               set_fiq_regs(&regs);
                enable_irq(dma->dma_irq);
        }
 }
@@ -83,6 +86,11 @@ void arch_disable_dma(dmach_t channel, dma_t *dma)
        }
 }
 
+int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns)
+{
+       return 0;
+}
+
 __initfunc(void arch_dma_init(dma_t *dma))
 {
        dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64;
index 27a139ad4abc6fc3f0f2e35609886cea9f9d41da..9be27bdaeb7f8420a543d3403065d8160e2ab962 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * arch/arm/kernel/dma-arc.c
  *
- * Copyright (C) 1998 Dave Gilbert / Russell King
+ * Copyright (C) 1998-1999 Dave Gilbert / Russell King
  *
  * DMA functions specific to Archimedes architecture
  */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 
@@ -14,7 +15,7 @@
 
 #include "dma.h"
 
-int arch_request_dma(dmach_t channel, dma_t *dma)
+int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id)
 {
        if (channel == DMA_VIRTUAL_FLOPPY0 ||
            channel == DMA_VIRTUAL_FLOPPY1)
@@ -25,16 +26,12 @@ int arch_request_dma(dmach_t channel, dma_t *dma)
 
 void arch_free_dma(dmach_t channel, dma_t *dma)
 {
-       if (channel != DMA_VIRTUAL_FLOPPY0 &&
-           channel != DMA_VIRTUAL_FLOPPY1)
-               return 0;
-       else
-               return -EINVAL;
 }
 
 void arch_enable_dma(dmach_t channel, dma_t *dma)
 {
        switch (channel) {
+#ifdef CONFIG_BLK_DEV_FD
        case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
                switch (dma->dma_mode) {
                case DMA_MODE_READ: /* read */
@@ -96,9 +93,38 @@ void arch_enable_dma(dmach_t channel, dma_t *dma)
                restore_flags(flags);
        }
        break;
+#endif
        }
 }
 
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+  switch (channel) {
+#ifdef CONFIG_BLK_DEV_FD
+    case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
+        extern unsigned int fdc1772_bytestogo;
+
+        /* 10/1/1999 DAG - I presume its the number of bytes left? */
+        return fdc1772_bytestogo;
+      };
+      break;
+
+    case DMA_VIRTUAL_FLOPPY1: { /* Command completed */
+        /* 10/1/1999 DAG - Presume whether there is an outstanding command? */
+        extern unsigned int fdc1772_fdc_int_done;
+
+        return (fdc1772_fdc_int_done==0)?1:0; /* Explicit! If the int done is 0 then 1 int to go */
+      };
+      break;
+
+#endif
+
+    default:
+      printk("dma-arc.c:arch_get_dma_residue called with unknown/unconfigured DMA channel\n");
+      return 0;
+  };
+}
+
 void arch_disable_dma(dmach_t channel, dma_t *dma)
 {
        if (channel != DMA_VIRTUAL_FLOPPY0 &&
@@ -108,6 +134,11 @@ void arch_disable_dma(dmach_t channel, dma_t *dma)
                disable_irq(dma->dma_irq);
 }
 
+int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns)
+{
+       return 0;
+}
+
 __initfunc(void arch_dma_init(dma_t *dma))
 {
        dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
index be72a89657b23ca42bd93633fe27d1b7cefce254..db46ef1c30f58a7a92880dbb82baa84347be5246 100644 (file)
@@ -9,6 +9,10 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <asm/spinlock.h>
+
+spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED;
+
 int request_dma(int channel, const char *device_id)
 {
        return -EINVAL;
diff --git a/arch/arm/kernel/dma-ebsa285.c b/arch/arm/kernel/dma-ebsa285.c
deleted file mode 100644 (file)
index f1c42da..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * arch/arm/kernel/dma-ebsa285.c
- *
- * Copyright (C) 1998 Phil Blundell
- *
- * DMA functions specific to EBSA-285/CATS architectures
- *
- * Changelog:
- *  09/11/1998 RMK     Split out ISA DMA functions to dma-isa.c
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/mman.h>
-#include <linux/init.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/hardware.h>
-
-#include "dma.h"
-#include "dma-isa.h"
-
-int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
-{
-       switch (channel) {
-       case 0:
-       case 1: /* 21285 internal channels */
-               return 0;
-
-       case 2 ... 9:
-               if (machine_is_cats())
-                       return isa_request_dma(channel - 2, dma, dev_name);
-       }
-
-       return -EINVAL;
-}
-
-void arch_free_dma(dmach_t channel, dma_t *dma)
-{
-       /* nothing to do */
-}
-
-int arch_get_dma_residue(dmach_t channel, dma_t *dma)
-{
-       int residue = 0;
-
-       switch (channel) {
-       case 0:
-       case 1:
-               break;
-#ifdef CONFIG_CATS
-       case 2 ... 9:
-               if (machine_is_cats())
-                       residue = isa_get_dma_residue(channel - 2);
-#endif
-       }
-       return residue;
-}
-
-void arch_enable_dma(dmach_t channel, dma_t *dma)
-{
-       switch (channel) {
-       case 0:
-       case 1:
-               /*
-                * Not yet implemented
-                */
-               break;
-#ifdef CONFIG_CATS
-       case 2 ... 9:
-               if (machine_is_cats())
-                       isa_enable_dma(channel - 2, dma);
-#endif
-       }
-}
-
-void arch_disable_dma(dmach_t channel, dma_t *dma)
-{
-       switch (channel) {
-       case 0:
-       case 1:
-               /*
-                * Not yet implemented
-                */
-               break;
-#ifdef CONFIG_CATS
-       case 2 ... 9:
-               if (machine_is_cats())
-                       isa_disable_dma(channel - 2, dma);
-#endif
-       }
-}
-
-__initfunc(void arch_dma_init(dma_t *dma))
-{
-       /* Nothing to do */
-}
diff --git a/arch/arm/kernel/dma-footbridge.c b/arch/arm/kernel/dma-footbridge.c
new file mode 100644 (file)
index 0000000..a355283
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * arch/arm/kernel/dma-ebsa285.c
+ *
+ * Copyright (C) 1998 Phil Blundell
+ *
+ * DMA functions specific to EBSA-285/CATS architectures
+ *
+ * Changelog:
+ *  09-Nov-1998        RMK     Split out ISA DMA functions to dma-isa.c
+ *  17-Mar-1999        RMK     Allow any EBSA285-like architecture to have
+ *                     ISA DMA controllers.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+#include "dma-isa.h"
+
+#ifdef CONFIG_ISA_DMA
+static int has_isa_dma;
+#else
+#define has_isa_dma 0
+#endif
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
+{
+       switch (channel) {
+       case _DC21285_DMA(0):
+       case _DC21285_DMA(1):   /* 21285 internal channels */
+               return 0;
+
+       case _ISA_DMA(0) ... _ISA_DMA(7):
+               if (has_isa_dma)
+                       return isa_request_dma(channel - _ISA_DMA(0), dma, dev_name);
+       }
+
+       return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+       /* nothing to do */
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+       int residue = 0;
+
+       switch (channel) {
+       case _DC21285_DMA(0):
+       case _DC21285_DMA(1):
+               break;
+
+       case _ISA_DMA(0) ... _ISA_DMA(7):
+               if (has_isa_dma)
+                       residue = isa_get_dma_residue(channel - _ISA_DMA(0), dma);
+       }
+       return residue;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+       switch (channel) {
+       case _DC21285_DMA(0):
+       case _DC21285_DMA(1):
+               /*
+                * Not yet implemented
+                */
+               break;
+
+       case _ISA_DMA(0) ... _ISA_DMA(7):
+               if (has_isa_dma)
+                       isa_enable_dma(channel - _ISA_DMA(0), dma);
+       }
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+       switch (channel) {
+       case _DC21285_DMA(0):
+       case _DC21285_DMA(1):
+               /*
+                * Not yet implemented
+                */
+               break;
+
+       case _ISA_DMA(0) ... _ISA_DMA(7):
+               if (has_isa_dma)
+                       isa_disable_dma(channel - _ISA_DMA(0), dma);
+       }
+}
+
+int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns)
+{
+       return 0;
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+#ifdef CONFIG_ISA_DMA
+       has_isa_dma = isa_init_dma();
+#endif
+}
index bdf7c614730e725b626a7cab0a7bc416ca67df74..19be50433a77d134d6598bd09a7bdccfd531990d 100644 (file)
@@ -11,6 +11,7 @@
  *  Copyright (C) 1998 Phil Blundell
  */
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/dma.h>
 #include <asm/io.h>
 #include "dma.h"
 #include "dma-isa.h"
 
+#define ISA_DMA_MODE_READ      0x44
+#define ISA_DMA_MODE_WRITE     0x48
+#define ISA_DMA_MODE_CASCADE   0xc0
+#define ISA_DMA_AUTOINIT       0x10
+
 #define ISA_DMA_MASK           0
 #define ISA_DMA_MODE           1
 #define ISA_DMA_CLRFF          2
@@ -40,10 +46,7 @@ static unsigned int isa_dma_port[8][7] = {
 
 int isa_request_dma(int channel, dma_t *dma, const char *dev_name)
 {
-       if (channel != 4)
-               return 0;
-
-       return -EINVAL;
+       return 0;
 }
 
 void isa_free_dma(int channel, dma_t *dma)
@@ -56,25 +59,27 @@ int isa_get_dma_residue(int channel, dma_t *dma)
        unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT];
        int count;
 
-       count = 1 + inb(io_port) + (inb(io_port) << 8);
+       count = 1 + inb(io_port);
+       count |= inb(io_port) << 8;
 
        return channel < 4 ? count : (count << 1);
 }
 
 void isa_enable_dma(int channel, dma_t *dma)
 {
-       unsigned long address, length;
-
        if (dma->invalid) {
+               unsigned long address, length;
+               unsigned int mode;
+
                address = dma->buf.address;
                length  = dma->buf.length - 1;
 
-               outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
                outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]);
+               outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
 
                if (channel >= 4) {
                        address >>= 1;
-                       length = (length >> 1) & 0xfe; /* why &0xfe? */
+                       length >>= 1;
                }
 
                outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]);
@@ -85,17 +90,31 @@ void isa_enable_dma(int channel, dma_t *dma)
                outb(length, isa_dma_port[channel][ISA_DMA_COUNT]);
                outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]);
 
-               outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]);
+               mode = channel & 3;
 
-               switch (dma->dma_mode) {
+               switch (dma->dma_mode & DMA_MODE_MASK) {
                case DMA_MODE_READ:
+                       mode |= ISA_DMA_MODE_READ;
                        dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length);
                        break;
 
                case DMA_MODE_WRITE:
+                       mode |= ISA_DMA_MODE_WRITE;
                        dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length);
                        break;
+
+               case DMA_MODE_CASCADE:
+                       mode |= ISA_DMA_MODE_CASCADE;
+                       break;
+
+               default:
+                       break;
                }
+
+               if (dma->dma_mode & DMA_AUTOINIT)
+                       mode |= ISA_DMA_AUTOINIT;
+
+               outb(mode, isa_dma_port[channel][ISA_DMA_MODE]);
                dma->invalid = 0;
        }
        outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]);
@@ -105,3 +124,56 @@ void isa_disable_dma(int channel, dma_t *dma)
 {
        outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]);
 }
+
+__initfunc(int isa_init_dma(void))
+{
+       int dmac_found;
+
+       outb(0xff, 0x0d);
+       outb(0xff, 0xda);
+
+       outb(0x55, 0x00);
+       outb(0xaa, 0x00);
+
+       dmac_found = inb(0x00) == 0x55 && inb(0x00) == 0xaa;
+
+       if (dmac_found) {
+               int channel;
+
+               for (channel = 0; channel < 8; channel++)
+                       isa_disable_dma(channel, NULL);
+
+               outb(0x40, 0x0b);
+               outb(0x41, 0x0b);
+               outb(0x42, 0x0b);
+               outb(0x43, 0x0b);
+
+               outb(0xc0, 0xd6);
+               outb(0x41, 0xd6);
+               outb(0x42, 0xd6);
+               outb(0x43, 0xd6);
+
+               outb(0, 0xd4);
+
+               outb(0x10, 0x08);
+               outb(0x10, 0xd0);
+
+               /*
+                * Is this correct?  According to
+                * my documentation, it doesn't
+                * appear to be.  It should be
+                * outb(0x3f, 0x40b); outb(0x3f, 0x4d6);
+                */
+               outb(0x30, 0x40b);
+               outb(0x31, 0x40b);
+               outb(0x32, 0x40b);
+               outb(0x33, 0x40b);
+               outb(0x31, 0x4d6);
+               outb(0x32, 0x4d6);
+               outb(0x33, 0x4d6);
+
+               request_dma(DMA_ISA_CASCADE, "cascade");
+       }
+
+       return dmac_found;
+}
index 3fcbdb3c73bd61b90e745adb522f7e8b8d62ba07..2640f6c3ac5f36bf90405baa978ed98fce407233 100644 (file)
@@ -23,3 +23,7 @@ void isa_enable_dma(int channel, dma_t *dma);
  */
 void isa_disable_dma(int channel, dma_t *dma);
 
+/*
+ * Initialise DMA
+ */
+int isa_init_dma(void);
index 00cd95e790a32ac2f384c51a6d0db9cd5a701c86..d3fcd911654e895c6b7ac68fbc2d2392407fc3b5 100644 (file)
 #include <linux/init.h>
 
 #include <asm/page.h>
-#include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/fiq.h>
 #include <asm/io.h>
+#include <asm/iomd.h>
 #include <asm/hardware.h>
 #include <asm/uaccess.h>
 
@@ -223,8 +223,9 @@ int arch_get_dma_residue(dmach_t channel, dma_t *dma)
                break;
 
        case DMA_VIRTUAL_FLOPPY: {
-               extern int floppy_fiqresidual(void);
-               residue = floppy_fiqresidual();
+               struct pt_regs regs;
+               get_fiq_regs(&regs);
+               return regs.ARM_r9;
                }
                break;
        }
@@ -286,7 +287,6 @@ void arch_enable_dma(dmach_t channel, dma_t *dma)
                set_fiq_handler(fiqhandler_start, fiqhandler_length);
                set_fiq_regs(&regs);
                enable_irq(dma->dma_irq);
-
                }
                break;
 
@@ -319,6 +319,46 @@ void arch_disable_dma(dmach_t channel, dma_t *dma)
        }
 }
 
+int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
+{
+       int tcr, speed;
+
+       if (cycle < 188)
+               speed = 3;
+       else if (cycle <= 250)
+               speed = 2;
+       else if (cycle < 438)
+               speed = 1;
+       else
+               speed = 0;
+
+       tcr = inb(IOMD_DMATCR);
+       speed &= 3;
+
+       switch (channel) {
+       case DMA_0:
+               tcr = (tcr & ~0x03) | speed;
+               break;
+
+       case DMA_1:
+               tcr = (tcr & ~0x0c) | (speed << 2);
+               break;
+
+       case DMA_2:
+               tcr = (tcr & ~0x30) | (speed << 4);
+               break;
+
+       case DMA_3:
+               tcr = (tcr & ~0xc0) | (speed << 6);
+               break;
+
+       default:
+               break;
+       }
+
+       outb(tcr, IOMD_DMATCR);
+}
+
 __initfunc(void arch_dma_init(dma_t *dma))
 {
        outb(0, IOMD_IO0CR);
@@ -326,7 +366,7 @@ __initfunc(void arch_dma_init(dma_t *dma))
        outb(0, IOMD_IO2CR);
        outb(0, IOMD_IO3CR);
 
-//     outb(0xf0, IOMD_DMATCR);
+       outb(0xa0, IOMD_DMATCR);
 
        dma[0].dma_base = ioaddr(IOMD_IO0CURA);
        dma[0].dma_irq  = IRQ_DMA0;
diff --git a/arch/arm/kernel/dma-vnc.c b/arch/arm/kernel/dma-vnc.c
deleted file mode 100644 (file)
index 132fa62..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * arch/arm/kernel/dma-vnc.c
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/mman.h>
-#include <linux/init.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/hardware.h>
-
-#include "dma.h"
-#include "dma-isa.h"
-
-int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
-{
-       if (channel < 8)
-               return isa_request_dma(channel, dma, dev_name);
-       return -EINVAL;
-}
-
-void arch_free_dma(dmach_t channel, dma_t *dma)
-{
-       isa_free_dma(channel, dma);
-}
-
-int arch_get_dma_residue(dmach_t channel, dma_t *dma)
-{
-       return isa_get_dma_residue(channel, dma);
-}
-
-void arch_enable_dma(dmach_t channel, dma_t *dma)
-{
-       isa_enable_dma(channel, dma);
-}
-
-void arch_disable_dma(dmach_t channel, dma_t *dma)
-{
-       isa_disable_dma(channel, dma);
-}
-
-__initfunc(void arch_dma_init(dma_t *dma))
-{
-       /* Nothing to do */
-}
-
index a164073ae41d858a7df0a806a5a9bef9f5015e7a..219e1f0f273d07fcaed63f9632f9828397cfd526 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/init.h>
 
 #include <asm/page.h>
-#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -201,6 +200,12 @@ void disable_dma (dmach_t channel)
                printk (KERN_ERR "Trying to disable free DMA%d\n", channel);
 }
 
+void set_dma_speed(dmach_t channel, int cycle_ns)
+{
+       dma_chan[channel].speed =
+          arch_set_dma_speed(channel, &dma_chan[channel], cycle_ns);
+}
+
 int get_dma_residue(dmach_t channel)
 {
        return arch_get_dma_residue(channel, &dma_chan[channel]);
@@ -214,6 +219,7 @@ EXPORT_SYMBOL(set_dma_count);
 EXPORT_SYMBOL(set_dma_mode);
 EXPORT_SYMBOL(get_dma_residue);
 EXPORT_SYMBOL(set_dma_sg);
+EXPORT_SYMBOL(set_dma_speed);
 
 __initfunc(void init_dma(void))
 {
index e4c72c6af17a536172e99946fa5985cd57852882..33db3b03ba39289b8cb8e36e835a5d4c31354000 100644 (file)
@@ -15,6 +15,7 @@ typedef struct {
        unsigned int    active:1;       /* Transfer active              */
        unsigned int    invalid:1;      /* Address/Count changed        */
        dmamode_t       dma_mode;       /* DMA mode                     */
+       int             speed;          /* DMA speed                    */
 
        unsigned int    lock;           /* Device is allocated          */
        const char      *device_id;     /* Device name                  */
@@ -63,6 +64,15 @@ void arch_disable_dma(dmach_t channel, dma_t *dma);
  */
 int arch_get_dma_residue(dmach_t channel, dma_t *dma);
 
+/* Prototype: int arch_set_dma_speed(channel, dma, cycle)
+ * Purpose  : Convert a cycle time to a register setting
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ *          : cycle   - cycle time in NS
+ * Returns  : setting for 'dma->speed'
+ */
+int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle);
+
 /* Prototype: void arch_dma_init(dma)
  * Purpose  : Initialise architecture specific DMA
  * Params   : dma - pointer to array of DMA structures
index fe1c75f5c8dbcf45eca823710d9b6ded37cdb439..dd4bf670cd4ae563c8ef71d84f868a79ab8a1b28 100644 (file)
@@ -7,32 +7,43 @@
  *
  * Created from information from Acorns RiscOS3 PRMs
  *
- * 08-Dec-1996 RMK     Added code for the 9'th expansion card - the ether podule slot.
+ * 08-Dec-1996 RMK     Added code for the 9'th expansion card - the ether
+ *                     podule slot.
  * 06-May-1997  RMK    Added blacklist for cards whose loader doesn't work.
- * 12-Sep-1997 RMK     Created new handling of interrupt enables/disables - cards can
- *                     now register their own routine to control interrupts (recommended).
- * 29-Sep-1997 RMK     Expansion card interrupt hardware not being re-enabled on reset from
- *                     Linux. (Caused cards not to respond under RiscOS without hard reset).
+ * 12-Sep-1997 RMK     Created new handling of interrupt enables/disables
+ *                     - cards can now register their own routine to control
+ *                     interrupts (recommended).
+ * 29-Sep-1997 RMK     Expansion card interrupt hardware not being re-enabled
+ *                     on reset from Linux. (Caused cards not to respond
+ *                     under RiscOS without hard reset).
  * 15-Feb-1998 RMK     Added DMA support
  * 12-Sep-1998 RMK     Added EASI support
+ * 10-Jan-1999 RMK     Run loaders in a simulated RISC OS environment.
+ * 17-Apr-1999 RMK     Support for EASI Type C cycles.
  */
 
 #define ECARD_C
+#define __KERNEL_SYSCALLS__
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-#include <asm/hardware.h>
+#include <asm/dma.h>
 #include <asm/ecard.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/dma.h>
+#include <asm/pgtable.h>
 
 #ifdef CONFIG_ARCH_ARC
 #include <asm/arch/oldlatches.h>
 #define oldlatch_init()
 #endif
 
-#define BLACKLIST_NAME(m,p,s)  { m, p, NULL, s }
-#define BLACKLIST_LOADER(m,p,l)        { m, p, l, NULL }
-#define BLACKLIST_NOLOADER(m,p)        { m, p, noloader, blacklisted_str }
-#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+enum req {
+       req_readbytes,
+       req_reset
+};
 
-extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[];
-static const char blacklisted_str[] = "*loader s/w is not 32-bit compliant*";
+struct ecard_request {
+       enum req        req;
+       ecard_t         *ec;
+       unsigned int    address;
+       unsigned int    length;
+       unsigned int    use_loader;
+       void            *buffer;
+};
 
-static const struct expcard_blacklist {
+struct expcard_blacklist {
        unsigned short   manufacturer;
        unsigned short   product;
-       const loader_t   loader;
        const char      *type;
-} blacklist[] = {
-/* Cards without names */
-    BLACKLIST_NAME(MANU_ACORN,         PROD_ACORN_ETHER1,      "Acorn Ether1"),
-
-/* Cards with corrected loader */
-  BLACKLIST_LOADER(MANU_ATOMWIDE,      PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader),
-  BLACKLIST_LOADER(MANU_OAK,           PROD_OAK_SCSI,          oak_scsi_loader),
+};
 
-/* Supported cards with broken loader */
-  { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI" },
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+static unsigned int ectcr;
+#ifdef HAS_EXPMASK
+static unsigned int have_expmask;
+#endif
 
-/* Unsupported cards with no loader */
-  BLACKLIST_NOLOADER(MANU_MCS,         PROD_MCS_CONNECT32)
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static const struct expcard_blacklist __init blacklist[] = {
+       { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
 };
 
+asmlinkage extern int
+ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
 extern int setup_arm_irq(int, struct irqaction *);
+extern void do_ecard_IRQ(int, struct pt_regs *);
+
+
+static void
+ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs);
+
+static struct irqaction irqexpansioncard = {
+       ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL
+};
+
+static inline unsigned short
+ecard_getu16(unsigned char *v)
+{
+       return v[0] | v[1] << 8;
+}
 
+static inline signed long
+ecard_gets24(unsigned char *v)
+{
+       return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+static inline ecard_t *
+slot_to_ecard(unsigned int slot)
+{
+       return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
 /*
- * from linux/arch/arm/kernel/irq.c
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors.  This
+ * may be a misplaced trust.
  */
-extern void do_ecard_IRQ(int irq, struct pt_regs *);
+#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+#define POD_INT_ADDR(x)        ((volatile unsigned char *)\
+                        ((BUS_ADDR((x)) - IO_BASE) + IO_START))
 
-static ecard_t expcard[MAX_ECARDS];
-static signed char irqno_to_expcard[16];
-static unsigned int ecard_numcards, ecard_numirqcards;
-static unsigned int have_expmask;
+static void
+ecard_task_reset(struct ecard_request *req)
+{
+       if (req->ec == NULL) {
+               ecard_t *ec;
+
+               for (ec = cards; ec; ec = ec->next) {
+                       printk(KERN_DEBUG "Resetting card %d\n",
+                              ec->slot_no);
+
+                       if (ec->loader)
+                               ecard_loader_reset(POD_INT_ADDR(ec->podaddr),
+                                                  ec->loader);
+               }
+               printk(KERN_DEBUG "All cards reset\n");
+       } else if (req->ec->loader)
+               ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr),
+                                  req->ec->loader);
+}
+
+static void
+ecard_task_readbytes(struct ecard_request *req)
+{
+       unsigned char *buf = (unsigned char *)req->buffer;
+       volatile unsigned char *base_addr =
+               (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
+       unsigned int len = req->length;
+
+       if (req->ec->slot_no == 8) {
+               /*
+                * The card maintains an index which
+                * increments the address into a 4096-byte
+                * page on each access.  We need to keep
+                * track of the counter.
+                */
+               static unsigned int index;
+               unsigned int offset, page;
+               unsigned char byte = 0; /* keep gcc quiet */
+
+               offset = req->address & 4095;
+               page   = req->address >> 12;
+
+               if (page > 256)
+                       return;
+
+               page *= 4;
+
+               if (offset == 0 || index > offset) {
+                       /*
+                        * We need to reset the index counter.
+                        */
+                       *base_addr = 0;
+                       index = 0;
+               }
+
+               while (index <= offset) {
+                       byte = base_addr[page];
+                       index += 1;
+               }
+
+               while (len--) {
+                       *buf++ = byte;
+                       if (len) {
+                               byte = base_addr[page];
+                               index += 1;
+                       }
+               }
+       } else {
+               unsigned int off = req->address;
+
+               if (!req->use_loader || !req->ec->loader) {
+                       off *= 4;
+                       while (len--) {
+                               *buf++ = base_addr[off];
+                               off += 4;
+                       }
+               } else {
+                       while(len--) {
+                               /*
+                                * The following is required by some
+                                * expansion card loader programs.
+                                */
+                               *(unsigned long *)0x108 = 0;
+                               *buf++ = ecard_loader_read(off++, base_addr,
+                                                          req->ec->loader);
+                       }
+               }
+       }
+
+}
+
+#ifdef CONFIG_CPU_32
+static pid_t ecard_pid;
+static wait_queue_head_t ecard_wait;
+static wait_queue_head_t ecard_done;
+static struct ecard_request *ecard_req;
+
+/*
+ * Set up the expansion card daemon's environment.
+ */
+static void
+ecard_init_task(void)
+{
+       /* We want to set up the page tables for the following mapping:
+        *  Virtual     Physical
+        *  0x03000000  0x03000000
+        *  0x03010000  unmapped
+        *  0x03210000  0x03210000
+        *  0x03400000  unmapped
+        *  0x08000000  0x08000000
+        *  0x10000000  unmapped
+        *
+        * FIXME: we don't follow this 100% yet.
+        */
+       pgd_t *src_pgd, *dst_pgd;
+       unsigned int dst_addr = IO_START;
+
+       src_pgd = pgd_offset(current->mm, IO_BASE);
+       dst_pgd = pgd_offset(current->mm, dst_addr);
+
+       while (dst_addr < IO_START + IO_SIZE) {
+               *dst_pgd++ = *src_pgd++;
+               dst_addr += PGDIR_SIZE;
+       }
+
+       flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE);
+
+       dst_addr = EASI_START;
+       src_pgd = pgd_offset(current->mm, EASI_BASE);
+       dst_pgd = pgd_offset(current->mm, dst_addr);
+
+       while (dst_addr < EASI_START + EASI_SIZE) {
+               *dst_pgd++ = *src_pgd++;
+               dst_addr += PGDIR_SIZE;
+       }
+
+       flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int
+ecard_task(void * unused)
+{
+       current->session = 1;
+       current->pgrp = 1;
+
+       /*
+        * We don't want /any/ signals, not even SIGKILL
+        */
+       sigfillset(&current->blocked);
+       sigemptyset(&current->signal);
+
+       strcpy(current->comm, "kecardd");
+
+       /*
+        * Set up the environment
+        */
+       ecard_init_task();
+
+       while (1) {
+               struct ecard_request *req;
+
+               do {
+                       req = xchg(&ecard_req, NULL);
+
+                       if (req == NULL) {
+                               sigemptyset(&current->signal);
+                               interruptible_sleep_on(&ecard_wait);
+                       }
+               } while (req == NULL);
+
+               switch (req->req) {
+               case req_readbytes:
+                       ecard_task_readbytes(req);
+                       break;
+
+               case req_reset:
+                       ecard_task_reset(req);
+                       break;
+               }
+               wake_up(&ecard_done);
+       }
+}
+
+/*
+ * Wake the expansion card daemon to action our request.
+ *
+ * FIXME: The test here is not sufficient to detect if the
+ * kcardd is running.
+ */
+static inline void
+ecard_call(struct ecard_request *req)
+{
+       /*
+        * If we're called from task 0, or from an
+        * interrupt (will be keyboard interrupt),
+        * we forcefully set up the memory map, and
+        * call the loader.  We can't schedule, or
+        * sleep for this call.
+        */
+       if ((current == task[0] || in_interrupt()) &&
+           req->req == req_reset && req->ec == NULL) {
+               ecard_init_task();
+               ecard_task_reset(req);
+       } else {
+               if (ecard_pid <= 0)
+                       ecard_pid = kernel_thread(ecard_task, NULL, 0);
+
+               ecard_req = req;
+
+               wake_up(&ecard_wait);
+
+               sleep_on(&ecard_done);
+       }
+}
+#else
+/*
+ * On 26-bit processors, we don't need the kcardd thread to access the
+ * expansion card loaders.  We do it directly.
+ */
+static inline void
+ecard_call(struct ecard_request *req)
+{
+       if (req->req == req_reset)
+               ecard_task_reset(req);
+       else
+               ecard_task_readbytes(req);
+}
+#endif
+
+/* ======================= Mid-level card control ===================== */
+/*
+ * This is called to reset the loaders for each expansion card on reboot.
+ *
+ * This is required to make sure that the card is in the correct state
+ * that RiscOS expects it to be.
+ */
+void
+ecard_reset(int slot)
+{
+       struct ecard_request req;
+
+       req.req = req_reset;
+
+       if (slot < 0)
+               req.ec = NULL;
+       else
+               req.ec = slot_to_ecard(slot);
+
+       ecard_call(&req);
+
+#ifdef HAS_EXPMASK
+       if (have_expmask && slot < 0) {
+               have_expmask |= ~0;
+               EXPMASK_ENABLE = have_expmask;
+       }
+#endif
+}
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+       struct ecard_request req;
+
+       req.req         = req_readbytes;
+       req.ec          = ec;
+       req.address     = off;
+       req.length      = len;
+       req.use_loader  = useld;
+       req.buffer      = addr;
+
+       ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+       struct ex_chunk_dir excd;
+       int index = 16;
+       int useld = 0;
+
+       if (!ec->cid.cd)
+               return 0;
+
+       while(1) {
+               ecard_readbytes(&excd, ec, index, 8, useld);
+               index += 8;
+               if (c_id(&excd) == 0) {
+                       if (!useld && ec->loader) {
+                               useld = 1;
+                               index = 0;
+                               continue;
+                       }
+                       return 0;
+               }
+               if (c_id(&excd) == 0xf0) { /* link */
+                       index = c_start(&excd);
+                       continue;
+               }
+               if (c_id(&excd) == 0x80) { /* loader */
+                       if (!ec->loader) {
+                               ec->loader = (loader_t)kmalloc(c_len(&excd),
+                                                              GFP_KERNEL);
+                               if (ec->loader)
+                                       ecard_readbytes(ec->loader, ec,
+                                                       (int)c_start(&excd),
+                                                       c_len(&excd), useld);
+                               else
+                                       return 0;
+                       }
+                       continue;
+               }
+               if (c_id(&excd) == id && num-- == 0)
+                       break;
+       }
+
+       if (c_id(&excd) & 0x80) {
+               switch (c_id(&excd) & 0x70) {
+               case 0x70:
+                       ecard_readbytes((unsigned char *)excd.d.string, ec,
+                                       (int)c_start(&excd), c_len(&excd),
+                                       useld);
+                       break;
+               case 0x00:
+                       break;
+               }
+       }
+       cd->start_offset = c_start(&excd);
+       memcpy(cd->d.string, excd.d.string, 256);
+       return 1;
+}
+
+/* ======================= Interrupt control ============================ */
 
 static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
 {
@@ -100,6 +486,11 @@ static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
 #endif
 }
 
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+       return !ec->irqmask || ec->irqaddr[0] & ec->irqmask;
+}
+
 static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
 {
        panic("ecard_def_fiq_enable called - impossible");
@@ -110,11 +501,18 @@ static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
        panic("ecard_def_fiq_disable called - impossible");
 }
 
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+       return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask;
+}
+
 static expansioncard_ops_t ecard_default_ops = {
        ecard_def_irq_enable,
        ecard_def_irq_disable,
+       ecard_def_irq_pending,
        ecard_def_fiq_enable,
-       ecard_def_fiq_disable
+       ecard_def_fiq_disable,
+       ecard_def_fiq_pending
 };
 
 /*
@@ -125,10 +523,9 @@ static expansioncard_ops_t ecard_default_ops = {
  */
 void ecard_enableirq(unsigned int irqnr)
 {
-       irqnr &= 7;
-       if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
-               ecard_t *ec = expcard + irqno_to_expcard[irqnr];
+       ecard_t *ec = slot_to_ecard(irqnr - 32);
 
+       if (ec) {
                if (!ec->ops)
                        ec->ops = &ecard_default_ops;
 
@@ -142,10 +539,9 @@ void ecard_enableirq(unsigned int irqnr)
 
 void ecard_disableirq(unsigned int irqnr)
 {
-       irqnr &= 7;
-       if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
-               ecard_t *ec = expcard + irqno_to_expcard[irqnr];
+       ecard_t *ec = slot_to_ecard(irqnr - 32);
 
+       if (ec) {
                if (!ec->ops)
                        ec->ops = &ecard_default_ops;
 
@@ -156,10 +552,9 @@ void ecard_disableirq(unsigned int irqnr)
 
 void ecard_enablefiq(unsigned int fiqnr)
 {
-       fiqnr &= 7;
-       if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
-               ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
+       ecard_t *ec = slot_to_ecard(fiqnr);
 
+       if (ec) {
                if (!ec->ops)
                        ec->ops = &ecard_default_ops;
 
@@ -173,10 +568,9 @@ void ecard_enablefiq(unsigned int fiqnr)
 
 void ecard_disablefiq(unsigned int fiqnr)
 {
-       fiqnr &= 7;
-       if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
-               ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
+       ecard_t *ec = slot_to_ecard(fiqnr);
 
+       if (ec) {
                if (!ec->ops)
                        ec->ops = &ecard_default_ops;
 
@@ -185,41 +579,89 @@ void ecard_disablefiq(unsigned int fiqnr)
        }
 }
 
-static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
+static void
+ecard_dump_irq_state(ecard_t *ec)
 {
-       const int num_cards = ecard_numirqcards;
-       int i, called = 0;
+       printk("  %d: %sclaimed, ",
+              ec->slot_no,
+              ec->claimed ? "" : "not ");
+
+       if (ec->ops && ec->ops->irqpending &&
+           ec->ops != &ecard_default_ops)
+               printk("irq %spending\n",
+                      ec->ops->irqpending(ec) ? "" : "not ");
+       else
+               printk("irqaddr %p, mask = %02X, status = %02X\n",
+                      ec->irqaddr, ec->irqmask, *ec->irqaddr);
+}
 
-       for (i = 0; i < num_cards; i++) {
-               if (expcard[i].claimed && expcard[i].irq &&
-                   (!expcard[i].irqmask ||
-                    expcard[i].irqaddr[0] & expcard[i].irqmask)) {
-                       do_ecard_IRQ(expcard[i].irq, regs);
-                       called ++;
+static void
+ecard_check_lockup(void)
+{
+       static int last, lockup;
+       ecard_t *ec;
+
+       /*
+        * If the timer interrupt has not run since the last million
+        * unrecognised expansion card interrupts, then there is
+        * something seriously wrong.  Disable the expansion card
+        * interrupts so at least we can continue.
+        *
+        * Maybe we ought to start a timer to re-enable them some time
+        * later?
+        */
+       if (last == jiffies) {
+               lockup += 1;
+               if (lockup > 1000000) {
+                       printk(KERN_ERR "\nInterrupt lockup detected - "
+                              "disabling all expansion card interrupts\n");
+
+                       disable_irq(IRQ_EXPANSIONCARD);
+
+                       printk("Expansion card IRQ state:\n");
+
+                       for (ec = cards; ec; ec = ec->next)
+                               ecard_dump_irq_state(ec);
                }
+       } else
+               lockup = 0;
+
+       /*
+        * If we did not recognise the source of this interrupt,
+        * warn the user, but don't flood the user with these messages.
+        */
+       if (!last || time_after(jiffies, last + 5*HZ)) {
+               last = jiffies;
+               printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
        }
-       cli();
-       if (called == 0) {
-               static int last, lockup;
-
-               if (last == jiffies) {
-                       lockup += 1;
-                       if (lockup > 1000000) {
-                               printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n");
-                               disable_irq(intr_no);
-                               printk("Expansion card IRQ state:\n");
-                               for (i = 0; i < num_cards; i++)
-                                       printk("  %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32,
-                                               expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr);
-                       }
-               } else
-                       lockup = 0;
+}
+
+static void
+ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
+{
+       ecard_t *ec;
+       int called = 0;
+
+       for (ec = cards; ec; ec = ec->next) {
+               int pending;
+
+               if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
+                       continue;
 
-               if (!last || time_after(jiffies, last + 5*HZ)) {
-                       last = jiffies;
-                       printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
+               if (ec->ops && ec->ops->irqpending)
+                       pending = ec->ops->irqpending(ec);
+               else
+                       pending = ecard_default_ops.irqpending(ec);
+
+               if (pending) {
+                       do_ecard_IRQ(ec->irq, regs);
+                       called ++;
                }
        }
+       cli();
+
+       if (called == 0)
+               ecard_check_lockup();
 }
 
 #ifdef HAS_EXPMASK
@@ -234,31 +676,35 @@ static unsigned char first_set[] =
        0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
 };
 
-static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
+static void
+ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
 {
        const unsigned int statusmask = 15;
        unsigned int status;
 
        status = EXPMASK_STATUS & statusmask;
        if (status) {
-               unsigned int irqno;
+               unsigned int slot;
                ecard_t *ec;
 again:
-               irqno = first_set[status];
-               ec = expcard + irqno_to_expcard[irqno];
+               slot = first_set[status];
+               ec = slot_to_ecard(slot);
                if (ec->claimed) {
                        unsigned int oldexpmask;
                        /*
-                        * this ugly code is so that we can operate a prioritorising system.
+                        * this ugly code is so that we can operate a
+                        * prioritorising system:
+                        *
                         * Card 0       highest priority
                         * Card 1
                         * Card 2
                         * Card 3       lowest priority
+                        *
                         * Serial cards should go in 0/1, ethernet/scsi in 2/3
                         * otherwise you will lose serial data at high speeds!
                         */
                        oldexpmask = have_expmask;
-                       EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]);
+                       EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]);
                        sti();
                        do_ecard_IRQ(ec->irq, regs);
                        cli();
@@ -267,15 +713,18 @@ again:
                        if (status)
                                goto again;
                } else {
-                       printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
-                       EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno));
+                       printk(KERN_WARNING "card%d: interrupt from unclaimed "
+                              "card???\n", slot);
+                       EXPMASK_ENABLE = (have_expmask &= ~(1 << slot));
                }
        } else
                printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
 }
 
-static int ecard_checkirqhw(void)
+__initfunc(static void
+ecard_probeirqhw(void))
 {
+       ecard_t *ec;
        int found;
 
        EXPMASK_ENABLE = 0x00;
@@ -283,62 +732,80 @@ static int ecard_checkirqhw(void)
        found = ((EXPMASK_STATUS & 15) == 0);
        EXPMASK_ENABLE = 0xff;
 
-       return found;
+       if (!found)
+               return;
+
+       printk(KERN_DEBUG "Expansion card interrupt "
+              "management hardware found\n");
+
+       irqexpansioncard.handler = ecard_irq_expmask;
+
+       /* for each card present, set a bit to '1' */
+       have_expmask = 0x80000000;
+
+       for (ec = cards; ec; ec = ec->next)
+               have_expmask |= 1 << ec->slot_no;
+
+       EXPMASK_ENABLE = have_expmask;
 }
+#else
+#define ecard_probeirqhw()
+#endif
+
+#ifndef IO_EC_MEMC8_BASE
+#define IO_EC_MEMC8_BASE 0
 #endif
 
-static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
 {
-       extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader);
-       unsigned char *a = (unsigned char *)addr;
+       unsigned long address = 0;
+       int slot = ec->slot_no;
 
-       if (ec->slot_no == 8) {
-               static unsigned int lowaddress;
-               unsigned int laddr, haddr;
-               unsigned char byte = 0; /* keep gcc quiet */
+       if (ec->slot_no == 8)
+               return IO_EC_MEMC8_BASE;
 
-               laddr = off & 4095;     /* number of bytes to read from offset + base addr */
-               haddr = off >> 12;      /* offset into card from base addr */
+       ectcr &= ~(1 << slot);
 
-               if (haddr > 256)
-                       return;
+       switch (type) {
+       case ECARD_MEMC:
+               if (slot < 4)
+                       address = IO_EC_MEMC_BASE + (slot << 12);
+               break;
 
-               /*
-                * If we require a low address or address 0, then reset, and start again...
-                */
-               if (!off || lowaddress > laddr) {
-                       outb(0, ec->podaddr);
-                       lowaddress = 0;
-               }
-               while (lowaddress <= laddr) {
-                       byte = inb(ec->podaddr + haddr);
-                       lowaddress += 1;
-               }
-               while (len--) {
-                       *a++ = byte;
-                       if (len) {
-                               byte = inb(ec->podaddr + haddr);
-                               lowaddress += 1;
-                       }
-               }
-       } else {
-               if (!useld || !ec->loader) {
-                       while(len--)
-                               *a++ = inb(ec->podaddr + (off++));
-               } else {
-                       while(len--) {
-                               *(unsigned long *)0x108 = 0; /* hack for some loaders!!! */
-                               *a++ = ecard_loader_read(off++, BUS_ADDR(ec->podaddr), ec->loader);
-                       }
-               }
+       case ECARD_IOC:
+               if (slot < 4)
+                       address = IO_EC_IOC_BASE + (slot << 12);
+#ifdef IO_EC_IOC4_BASE
+               else
+                       address = IO_EC_IOC4_BASE + ((slot - 4) << 12);
+#endif
+               if (address)
+                       address +=  speed << 17;
+               break;
+
+#ifdef IO_EC_EASI_BASE
+       case ECARD_EASI:
+               address = IO_EC_EASI_BASE + (slot << 22);
+               if (speed == ECARD_FAST)
+                       ectcr |= 1 << slot;
+               break;
+#endif
        }
+
+#ifdef IOMD_ECTCR
+       outb(ectcr, IOMD_ECTCR);
+#endif
+       return address;
 }
 
+static const char *unknown = "*unknown*";
+
 static int ecard_prints(char *buffer, ecard_t *ec)
 {
        char *start = buffer;
 
-       buffer += sprintf(buffer, "\n  %d: ", ec->slot_no);
+       buffer += sprintf(buffer, "  %d: %s ", ec->slot_no,
+                         ec->type == ECARD_EASI ? "EASI" : "    ");
 
        if (ec->cid.id == 0) {
                struct in_chunk_dir incd;
@@ -346,28 +813,57 @@ static int ecard_prints(char *buffer, ecard_t *ec)
                buffer += sprintf(buffer, "[%04X:%04X] ",
                        ec->cid.manufacturer, ec->cid.product);
 
-               if (!ec->card_desc && ec->cid.is && ec->cid.cd &&
-                   ecard_readchunk(&incd, ec, 0xf5, 0))
-                       ec->card_desc = incd.d.string;
+               if (!ec->card_desc && ec->cid.cd &&
+                   ecard_readchunk(&incd, ec, 0xf5, 0)) {
+                       ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
 
-               if (!ec->card_desc)
-                       ec->card_desc = "*unknown*";
+                       if (ec->card_desc)
+                               strcpy(ec->card_desc, incd.d.string);
+               }
 
-               buffer += sprintf(buffer, "%s", ec->card_desc);
+               buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
        } else
-               buffer += sprintf(buffer, "Simple card %d", ec->cid.id);
+               buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id);
 
        return buffer - start;
 }
 
-static inline unsigned short ecard_getu16(unsigned char *v)
+int get_ecard_dev_info(char *buf, char **start, off_t pos, int count, int wr)
 {
-       return v[0] | v[1] << 8;
+       ecard_t *ec = cards;
+       off_t at = 0;
+       int len, cnt;
+
+       cnt = 0;
+       while (ec && count > cnt) {
+               len = ecard_prints(buf, ec);
+               at += len;
+               if (at >= pos) {
+                       if (!*start) {
+                               *start = buf + (pos - (at - len));
+                               cnt = at - pos;
+                       } else
+                               cnt += len;
+                       buf += len;
+               }
+               ec = ec->next;
+       }
+       return (count > cnt) ? cnt : count;
 }
 
-static inline signed long ecard_gets24(unsigned char *v)
+static struct proc_dir_entry proc_ecard_devices = {
+       PROC_BUS_ECARD_DEVICES, 7, "devices",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_array_inode_operations,
+       get_ecard_dev_info
+};
+
+static struct proc_dir_entry *proc_bus_ecard_dir;
+
+static void ecard_proc_init(void)
 {
-       return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+       proc_bus_ecard_dir = create_proc_entry("ecard", S_IFDIR, proc_bus);
+       proc_register(proc_bus_ecard_dir, &proc_ecard_devices);
 }
 
 /*
@@ -376,33 +872,39 @@ static inline signed long ecard_gets24(unsigned char *v)
  * If bit 1 of the first byte of the card is set, then the
  * card does not exist.
  */
-__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
+__initfunc(static int
+ecard_probe(int slot, card_type_t type))
 {
-       ecard_t *ec = expcard + freeslot;
+       ecard_t **ecp;
+       ecard_t *ec;
        struct ex_ecid cid;
        char buffer[200];
-       int i;
+       int i, rc = -ENOMEM;
+
+       ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
+
+       if (!ec)
+               goto nodev;
 
-       irqno_to_expcard[card] = -1;
+       memset(ec, 0, sizeof(ecard_t));
 
-       ec->slot_no     = card;
+       ec->slot_no     = slot;
+       ec->type        = type;
        ec->irq         = NO_IRQ;
        ec->fiq         = NO_IRQ;
        ec->dma         = NO_DMA;
        ec->card_desc   = NULL;
        ec->ops         = &ecard_default_ops;
 
+       rc = -ENODEV;
        if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
-               return 0;
+               goto nodev;
 
        cid.r_zero = 1;
        ecard_readbytes(&cid, ec, 0, 16, 0);
        if (cid.r_zero)
-               return 0;
+               goto nodev;
 
-       irqno_to_expcard[card] = freeslot;
-
-       ec->type        = type;
        ec->cid.id      = cid.r_id;
        ec->cid.cd      = cid.r_cd;
        ec->cid.is      = cid.r_is;
@@ -415,9 +917,9 @@ __initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
        ec->cid.fiqmask = cid.r_fiqmask;
        ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
        ec->fiqaddr     =
-       ec->irqaddr     = (unsigned char *)BUS_ADDR(ec->podaddr);
+       ec->irqaddr     = (unsigned char *)ioaddr(ec->podaddr);
 
-       if (ec->cid.cd && ec->cid.is) {
+       if (ec->cid.is) {
                ec->irqmask = ec->cid.irqmask;
                ec->irqaddr += ec->cid.irqoff;
                ec->fiqmask = ec->cid.fiqmask;
@@ -430,88 +932,69 @@ __initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
        for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
                if (blacklist[i].manufacturer == ec->cid.manufacturer &&
                    blacklist[i].product == ec->cid.product) {
-                       ec->loader = blacklist[i].loader;
                        ec->card_desc = blacklist[i].type;
                        break;
                }
 
-       ecard_prints(buffer, ec);
-       printk("%s", buffer);
-
-       ec->irq = 32 + card;
+       ec->irq = 32 + slot;
 #ifdef IO_EC_MEMC8_BASE
-       if (card == 8)
+       if (slot == 8)
                ec->irq = 11;
 #endif
 #ifdef CONFIG_ARCH_RPC
        /* On RiscPC, only first two slots have DMA capability */
-       if (card < 2)
-               ec->dma = 2 + card;
+       if (slot < 2)
+               ec->dma = 2 + slot;
 #endif
 #if 0  /* We don't support FIQs on expansion cards at the moment */
-       ec->fiq = 96 + card;
+       ec->fiq = 96 + slot;
 #endif
 
-       return 1;
-}
+       rc = 0;
 
-/*
- * This is called to reset the loaders for each expansion card on reboot.
- *
- * This is required to make sure that the card is in the correct state
- * that RiscOS expects it to be.
- */
-void ecard_reset(int card)
-{
-       extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader);
+       for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
 
-       if (card >= ecard_numcards)
-               return;
-    
-       if (card < 0) {
-               for (card = 0; card < ecard_numcards; card++)
-                       if (expcard[card].loader)
-                               ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
-                                                       expcard[card].loader);
-       } else
-               if (expcard[card].loader)
-                       ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
-                                               expcard[card].loader);
+       *ecp = ec;
 
-#ifdef HAS_EXPMASK
-       if (have_expmask) {
-               have_expmask |= ~0;
-               EXPMASK_ENABLE = have_expmask;
+nodev:
+       if (rc && ec)
+               kfree(ec);
+       else {
+               slot_to_expcard[slot] = ec;
+
+               ecard_prints(buffer, ec);
+               printk("%s", buffer);
        }
-#endif
+       return rc;
 }
 
-static unsigned int ecard_startcard;
+static ecard_t *finding_pos;
 
 void ecard_startfind(void)
 {
-       ecard_startcard = 0;
+       finding_pos = NULL;
 }
 
 ecard_t *ecard_find(int cid, const card_ids *cids)
 {
-       int card;
+       if (!finding_pos)
+               finding_pos = cards;
+       else
+               finding_pos = finding_pos->next;
+
+       for (; finding_pos; finding_pos = finding_pos->next) {
+               if (finding_pos->claimed)
+                       continue;
 
-       if (!cids) {
-               for (card = ecard_startcard; card < ecard_numcards; card++)
-                       if (!expcard[card].claimed &&
-                           (expcard[card].cid.id ^ cid) == 0)
+               if (!cids) {
+                       if ((finding_pos->cid.id ^ cid) == 0)
                                break;
-       } else {
-               for (card = ecard_startcard; card < ecard_numcards; card++) {
+               } else {
                        unsigned int manufacturer, product;
                        int i;
 
-                       if (expcard[card].claimed)
-                               continue;
-
-                       manufacturer = expcard[card].cid.manufacturer;
-                       product = expcard[card].cid.product;
+                       manufacturer = finding_pos->cid.manufacturer;
+                       product = finding_pos->cid.product;
 
                        for (i = 0; cids[i].manufacturer != 65535; i++)
                                if (manufacturer == cids[i].manufacturer &&
@@ -523,111 +1006,24 @@ ecard_t *ecard_find(int cid, const card_ids *cids)
                }
        }
 
-       ecard_startcard = card + 1;
-
-       return card < ecard_numcards ? &expcard[card] : NULL;
+       return finding_pos;
 }
 
-int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+__initfunc(static void ecard_free_all(void))
 {
-       struct ex_chunk_dir excd;
-       int index = 16;
-       int useld = 0;
+       ecard_t *ec, *ecn;
 
-       if (!ec->cid.is || !ec->cid.cd)
-               return 0;
-
-       while(1) {
-               ecard_readbytes(&excd, ec, index, 8, useld);
-               index += 8;
-               if (c_id(&excd) == 0) {
-                       if (!useld && ec->loader) {
-                               useld = 1;
-                               index = 0;
-                               continue;
-                       }
-                       return 0;
-               }
-               if (c_id(&excd) == 0xf0) { /* link */
-                       index = c_start(&excd);
-                       continue;
-               }
-               if (c_id(&excd) == 0x80) { /* loader */
-                       if (!ec->loader) {
-                               ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL);
-                               ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld);
-                       }
-                       continue;
-               }
-               if (c_id(&excd) == id && num-- == 0)
-                       break;
-       }
+       for (ec = cards; ec; ec = ecn) {
+               ecn = ec->next;
 
-       if (c_id(&excd) & 0x80) {
-               switch (c_id(&excd) & 0x70) {
-               case 0x70:
-                       ecard_readbytes((unsigned char *)excd.d.string, ec,
-                                       (int)c_start(&excd), c_len(&excd), useld);
-                       break;
-               case 0x00:
-                       break;
-               }
+               kfree(ec);
        }
-       cd->start_offset = c_start(&excd);
-       memcpy(cd->d.string, excd.d.string, 256);
-       return 1;
-}
-
-unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
-{
-       switch (ec->slot_no) {
-       case 0 ... 3:
-               switch (type) {
-               case ECARD_MEMC:
-                       return IO_EC_MEMC_BASE + (ec->slot_no << 12);
-
-               case ECARD_IOC:
-                       return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12);
-
-#ifdef IO_EC_EASI_BASE
-               case ECARD_EASI:
-                       return IO_EC_EASI_BASE + (ec->slot_no << 22);
-#endif
-               }
-               break;
 
-       case 4 ... 7:
-               switch (type) {
-#ifdef IO_EC_IOC4_BASE
-               case ECARD_IOC:
-                       return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
-#endif
-#ifdef IO_EC_EASI_BASE
-               case ECARD_EASI:
-                       return IO_EC_EASI_BASE + (ec->slot_no << 22);
-#endif
-               default:
-                       break;
-               }
-               break;
+       cards = NULL;
 
-#ifdef IO_EC_MEMC8_BASE
-       case 8:
-               return IO_EC_MEMC8_BASE;
-#endif
-       }
-       return 0;
+       memset(slot_to_expcard, 0, sizeof(slot_to_expcard));
 }
 
-static struct irqaction irqexpansioncard = {
-       ecard_irq_noexpmask,
-       SA_INTERRUPT,
-       0,
-       "expansion cards",
-       NULL,
-       NULL
-};
-
 /*
  * Initialise the expansion card system.
  * Locate all hardware - interrupt management and
@@ -635,51 +1031,38 @@ static struct irqaction irqexpansioncard = {
  */
 __initfunc(void ecard_init(void))
 {
-       int i, nc = 0;
+       int slot;
 
-       memset(expcard, 0, sizeof(expcard));
+       oldlatch_init();
 
-#ifdef HAS_EXPMASK
-       if (ecard_checkirqhw()) {
-               printk(KERN_DEBUG "Expansion card interrupt management hardware found\n");
-               irqexpansioncard.handler = ecard_irq_expmask;
-               irqexpansioncard.flags |= SA_IRQNOMASK;
-               have_expmask = -1;
-       }
+#ifdef CONFIG_CPU_32
+       init_waitqueue_head(&ecard_wait);
+       init_waitqueue_head(&ecard_done);
 #endif
 
-       printk("Installed expansion cards:");
+       printk("Probing expansion cards: (does not imply support)\n");
 
-       /*
-        * First of all, probe all cards on the expansion card interrupt line
-        */
-       for (i = 0; i < 8; i++)
-               if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI))
-                       nc += 1;
-               else
-                       have_expmask &= ~(1<<i);
-
-       ecard_numirqcards = nc;
+       for (slot = 0; slot < 8; slot ++) {
+               if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
+                       ecard_probe(slot, ECARD_IOC);
+       }
 
-       /* Now probe other cards with different interrupt lines
-        */
 #ifdef IO_EC_MEMC8_BASE
-       if (ecard_probe(8, nc, ECARD_IOC))
-               nc += 1;
+       ecard_probe(8, ECARD_IOC);
 #endif
 
-       printk("\n");
-       ecard_numcards = nc;
+       ecard_probeirqhw();
 
-       if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
-               printk("Could not allocate interrupt for expansion cards\n");
-               return;
+       if (setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
+               printk(KERN_ERR "Unable to claim IRQ%d for expansion cards\n",
+                      IRQ_EXPANSIONCARD);
+               ecard_free_all();
        }
-       
-#ifdef HAS_EXPMASK
-       if (nc && have_expmask)
-               EXPMASK_ENABLE = have_expmask;
-#endif
 
-       oldlatch_init();
+       ecard_proc_init();
 }
+
+EXPORT_SYMBOL(ecard_startfind);
+EXPORT_SYMBOL(ecard_find);
+EXPORT_SYMBOL(ecard_readchunk);
+EXPORT_SYMBOL(ecard_address);
index 3ca29cd2c5911ad36698bd7802880a6b82cb95aa..758163f07b8ba804b472badc276dae3b92769161 100644 (file)
@@ -159,8 +159,8 @@ irq_prio_h: .byte    0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
                .macro  restore_user_regs
                ldmia   sp, {r0 - lr}^
                mov     r0, r0
-               add     sp, sp, #15*4
-               ldr     lr, [sp], #8
+               ldr     lr, [sp, #15*4]
+               add     sp, sp, #15*4+8
                movs    pc, lr
                .endm
 
@@ -226,13 +226,6 @@ irq_prio_h:        .byte    0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
                str     r0, [sp, #S_OLD_R0]     ;\
                mov     fp, #0
 
-#define USER_RESTORE_ALL                       \
-               ldmia   sp, {r0 - lr}^          ;\
-               mov     r0, r0                  ;\
-               add     sp, sp, #15*4           ;\
-               ldr     lr, [sp], #8            ;\
-               movs    pc, lr
-
 #define SVC_RESTORE_ALL                                \
                ldmfd   sp, {r0 - pc}^
                
@@ -253,7 +246,7 @@ _unexp_fiq: ldr     sp, .LCfiq
                mov     r0, r0
                movs    pc, lr
 
-Lfiqmsg:       .ascii  "*** Unexpeced FIQ\n\0"
+Lfiqmsg:       .ascii  "*** Unexpected FIQ\n\0"
                .align
 
 .LCfiq:                .word   __temp_fiq
@@ -315,14 +308,14 @@ fpe_not_present:
                and     r4, r10, #255                   @ get offset
                and     r6, r10, #0x000f0000
                tst     r10, #0x00800000                @ +/-
-               rsbeq   r4, r4, #0
                ldr     r5, [sp, r6, lsr #14]           @ Load reg
+               rsbeq   r4, r4, #0
                add     r5, r5, r4, lsl #2
                str     r5, [sp, r6, lsr #14]           @ Save reg
                b       ret_from_exception
 
-wfs_mask_data: .word   0x0e200110                      @ WFS
-               .word   0x0fff0fff
+wfs_mask_data: .word   0x0e200110                      @ WFS/RFS
+               .word   0x0fef0fff
                .word   0x0d0d0100                      @ LDF [sp]/STF [sp]
                .word   0x0d0b0100                      @ LDF [fp]/STF [fp]
                .word   0x0f0f0f00
@@ -341,8 +334,7 @@ vector_prefetch:
                save_user_regs
                teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
                mask_pc r0, lr                  @ Address of abort
-               mov     r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code
-               mov     r2, sp                  @ Tasks registers
+               mov     r1, sp                  @ Tasks registers
                bl      SYMBOL_NAME(do_PrefetchAbort)
                teq     r0, #0                  @ If non-zero, we believe this abort..
                bne     ret_from_sys_call
@@ -451,6 +443,7 @@ vector_IRQ: ldr     r13, .LCirq                     @ I will leave this one in just in case...
                adr     lr, 1b
                orr     lr, lr, #0x08000003             @ Force SVC
                bne     do_IRQ
+               mov     r4, #0
                b       ret_with_reschedule
 
                irq_prio_table
@@ -562,8 +555,8 @@ Ldata_ldrstr_numindex:
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
-               biceq   r0, r0, #PCMASK
                mov     r1, r4, lsl #20
+               biceq   r0, r0, #PCMASK
                tst     r4, #1 << 23
                addne   r0, r0, r1, lsr #20
                subeq   r0, r0, r1, lsr #20
@@ -578,12 +571,12 @@ Ldata_ldrstr_regindex:
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
-               biceq   r0, r0, #PCMASK
                and     r7, r4, #15
+               biceq   r0, r0, #PCMASK
                teq     r7, #15                 @ Check for PC
                ldr     r7, [r3, r7, lsl #2]    @ Get Rm
-               biceq   r7, r7, #PCMASK
                and     r8, r4, #0x60           @ Get shift types
+               biceq   r7, r7, #PCMASK
                mov     r9, r4, lsr #7          @ Get shift amount
                and     r9, r9, #31
                teq     r8, #0
@@ -645,8 +638,8 @@ Ldata_ldcstc_pre:
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
-               biceq   r0, r0, #PCMASK
                mov     r1, r4, lsl #24         @ Get offset
+               biceq   r0, r0, #PCMASK
                tst     r4, #1 << 23
                addne   r0, r0, r1, lsr #24
                subeq   r0, r0, r1, lsr #24
@@ -656,9 +649,54 @@ Ldata_ldcstc_pre:
 #endif
                b       SYMBOL_NAME(do_DataAbort)
 
-#include "entry-common.S"
+/*
+ *=============================================================================
+ *             Low-level interface code
+ *-----------------------------------------------------------------------------
+ *             Trap initialisation
+ *-----------------------------------------------------------------------------
+ *
+ * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
+ * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
+ * some excess cycles).
+ *
+ * What we need to put into 0-0x1c are branches to branch to the kernel.
+ */
 
-               .data
+               .section ".text.init",#alloc,#execinstr
+
+.Ljump_addresses:
+               swi     SYS_ERROR0
+               .word   vector_undefinstr       - 12
+               .word   vector_swi              - 16
+               .word   vector_prefetch         - 20
+               .word   vector_data             - 24
+               .word   vector_addrexcptn       - 28
+               .word   vector_IRQ              - 32
+               .word   _unexp_fiq              - 36
+               b       . + 8
+/*
+ * initialise the trap system
+ */
+ENTRY(trap_init)
+               stmfd   sp!, {r4 - r7, lr}
+               adr     r1, .Ljump_addresses
+               ldmia   r1, {r1 - r7, ip, lr}
+               orr     r2, lr, r2, lsr #2
+               orr     r3, lr, r3, lsr #2
+               orr     r4, lr, r4, lsr #2
+               orr     r5, lr, r5, lsr #2
+               orr     r6, lr, r6, lsr #2
+               orr     r7, lr, r7, lsr #2
+               orr     ip, lr, ip, lsr #2
+               mov     r0, #0
+               stmia   r0, {r1 - r7, ip}
+               ldmfd   sp!, {r4 - r7, pc}^
+
+               .text
+
+#include "entry-common.S"
 
-__temp_irq:    .word   0                               @ saved lr_irq
+               .bss
+__temp_irq:    .space  4                               @ saved lr_irq
 __temp_fiq:    .space  128
index bcc938b3260e7e91c6cbff429ef4d4179afcfc0e..9456abe337d23404340b9eccbf8b6bc8431a3a22 100644 (file)
 #define S_R1           4
 #define S_R0           0
 
+#define OFF_CR_ALIGNMENT(x)    cr_alignment - x
+
 #ifdef IOC_BASE
 /* IOC / IOMD based hardware */
+#include <asm/iomd.h>
+
                .equ    ioc_base_high, IOC_BASE & 0xff000000
                .equ    ioc_base_low, IOC_BASE & 0x00ff0000
                .macro  disable_fiq
@@ -186,113 +190,109 @@ irq_prio_ebsa110:
                .byte    6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
                .endm
 
-#elif defined(CONFIG_ARCH_EBSA285)
+#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
+#include <asm/dec21285.h>
 
                .macro  disable_fiq
                .endm
 
+               .equ    irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000
+               .equ    irq_mask_pci_err_low,  IRQ_MASK_PCI_ERR & 0x00ffffff
+               .equ    dc21285_high, ARMCSR_BASE & 0xff000000
+               .equ    dc21285_low, ARMCSR_BASE & 0x00ffffff
+
                .macro  get_irqnr_and_base, irqnr, irqstat, base
-               mov     r4, #0xfe000000
+               mov     r4, #dc21285_high
+               .if     dc21285_low
+               orr     r4, r4, #dc21285_low
+               .endif
                ldr     \irqstat, [r4, #0x180]          @ get interrupts
-               mov     \irqnr, #0
-1001:          tst     \irqstat, #1
-               addeq   \irqnr, \irqnr, #1
-               moveq   \irqstat, \irqstat, lsr #1
-               tsteq   \irqnr, #32
-               beq     1001b
-               teq     \irqnr, #32
-               .endm
 
-               .macro  irq_prio_table
-               .endm
-
-#elif defined(CONFIG_ARCH_NEXUSPCI)
+               mov     \irqnr, #IRQ_SDRAMPARITY
+               tst     \irqstat, #IRQ_MASK_SDRAMPARITY
+               bne     1001f
 
-               .macro  disable_fiq
-               .endm
+               tst     \irqstat, #IRQ_MASK_UART_RX
+               movne   \irqnr, #IRQ_CONRX
+               bne     1001f
 
-               .macro  get_irqnr_and_base, irqnr, irqstat, base
-               ldr     r4, =0xffe00000
-               ldr     \irqstat, [r4, #0x180]          @ get interrupts
-               mov     \irqnr, #0
-1001:          tst     \irqstat, #1
-               addeq   \irqnr, \irqnr, #1
-               moveq   \irqstat, \irqstat, lsr #1
-               tsteq   \irqnr, #32
-               beq     1001b
-               teq     \irqnr, #32
-               .endm
+               tst     \irqstat, #IRQ_MASK_DMA1
+               movne   \irqnr, #IRQ_DMA1
+               bne     1001f
 
-               .macro  irq_prio_table
-               .endm
+               tst     \irqstat, #IRQ_MASK_DMA2
+               movne   \irqnr, #IRQ_DMA2
+               bne     1001f
 
-#elif defined(CONFIG_ARCH_VNC)
+               tst     \irqstat, #IRQ_MASK_IN0
+               movne   \irqnr, #IRQ_IN0
+               bne     1001f
 
-               .macro  disable_fiq
-               .endm
+               tst     \irqstat, #IRQ_MASK_IN1
+               movne   \irqnr, #IRQ_IN1
+               bne     1001f
 
-               .equ    pci_iack_high, PCI_IACK & 0xff000000
-               .equ    pci_iack_low,  PCI_IACK & 0x00ff0000
+               tst     \irqstat, #IRQ_MASK_IN2
+               movne   \irqnr, #IRQ_IN2
+               bne     1001f
 
-               .macro  get_irqnr_and_base, irqnr, irqstat, base
-               mov     r4, #IO_BASE_ARM_CSR
-               ldr     \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones
+               tst     \irqstat, #IRQ_MASK_IN3
+               movne   \irqnr, #IRQ_IN3
+               bne     1001f
 
-               @ run through hard priorities
-               @ timer
-               tst     \irqstat, #IRQ_MASK_TIMER0
-               movne   \irqnr, #IRQ_TIMER0
+               tst     \irqstat, #IRQ_MASK_PCI
+               movne   \irqnr, #IRQ_PCI
                bne     1001f
 
-               @ ether10
-               tst     \irqstat, #IRQ_MASK_ETHER10
-               movne   \irqnr, #IRQ_ETHER10
+               tst     \irqstat, #IRQ_MASK_I2OINPOST
+               movne   \irqnr, #IRQ_I2OINPOST
                bne     1001f
 
-               @ ether100
-               tst     \irqstat, #IRQ_MASK_ETHER100
-               movne   \irqnr, #IRQ_ETHER100
+               tst     \irqstat, #IRQ_MASK_TIMER1
+               movne   \irqnr, #IRQ_TIMER1
                bne     1001f
 
-               @ video compressor
-               tst     \irqstat, #IRQ_MASK_VIDCOMP
-               movne   \irqnr, #IRQ_VIDCOMP
+               tst     \irqstat, #IRQ_MASK_TIMER2
+               movne   \irqnr, #IRQ_TIMER2
                bne     1001f
 
-               @ now try all the PIC sources
-               @ determine whether we have an irq
-               tst     \irqstat, #IRQ_MASK_EXTERN_IRQ
-               beq     1002f
-               mov     r4, #pci_iack_high
-               orr     r4, r4, #pci_iack_low
-               ldrb    \irqnr, [r4]                    @ get the IACK byte
-               b       1001f
-
-1002:          @ PCI errors
-               tst     \irqstat, #IRQ_MASK_PCI_ERR
-               movne   \irqnr, #IRQ_PCI_ERR
+               tst     \irqstat, #IRQ_MASK_TIMER3
+               movne   \irqnr, #IRQ_TIMER3
                bne     1001f
 
-               @ softint
-               tst     \irqstat, #IRQ_MASK_SOFTIRQ
-               movne   \irqnr, #IRQ_SOFTIRQ
+               tst     \irqstat, #IRQ_MASK_UART_TX
+               movne   \irqnr, #IRQ_CONTX
                bne     1001f
 
-               @ debug uart
-               tst     \irqstat, #IRQ_MASK_UART_DEBUG
-               movne   \irqnr, #IRQ_CONRX
+               tst     \irqstat, #irq_mask_pci_err_high
+               tsteq   \irqstat, #irq_mask_pci_err_low
+               movne   \irqnr, #IRQ_PCI_ERR
                bne     1001f
+1001:
+               .endm
+
+               .macro  irq_prio_table
+               .endm
 
-               @ watchdog
-               tst     \irqstat, #IRQ_MASK_WATCHDOG
-               movne   \irqnr, #IRQ_WATCHDOG
+#elif defined(CONFIG_ARCH_NEXUSPCI)
 
-1001:          @ If Z is set, then we will not enter an interrupt
+               .macro  disable_fiq
                .endm
 
-               .macro  irq_prio_table
+               .macro  get_irqnr_and_base, irqnr, irqstat, base
+               ldr     r4, =0xffe00000
+               ldr     \irqstat, [r4, #0x180]          @ get interrupts
+               mov     \irqnr, #0
+1001:          tst     \irqstat, #1
+               addeq   \irqnr, \irqnr, #1
+               moveq   \irqstat, \irqstat, lsr #1
+               tsteq   \irqnr, #32
+               beq     1001b
+               teq     \irqnr, #32
                .endm
 
+               .macro  irq_prio_table
+               .endm
 #else
 #error Unknown architecture
 #endif
@@ -306,22 +306,22 @@ irq_prio_ebsa110:
                stmia   sp, {r0 - r12}                  @ Calling r0 - r12
                add     r8, sp, #S_PC
                stmdb   r8, {sp, lr}^                   @ Calling sp, lr
-               mov     r7, r0
+               str     lr, [r8, #0]                    @ Save calling PC
                mrs     r6, spsr
-               mov     r5, lr
-               stmia   r8, {r5, r6, r7}                @ Save calling PC, CPSR, OLD_R0
+               str     r6, [r8, #4]                    @ Save CPSR
+               str     r0, [r8, #8]                    @ Save OLD_R0
                .endm
 
                .macro  restore_user_regs
-               mrs     r0, cpsr                        @ disable IRQs
-               orr     r0, r0, #I_BIT
-               msr     cpsr, r0
+               mrs     r1, cpsr                        @ disable IRQs
+               orr     r1, r1, #I_BIT
                ldr     r0, [sp, #S_PSR]                @ Get calling cpsr
+               msr     cpsr, r1
                msr     spsr, r0                        @ save in spsr_svc
                ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
                mov     r0, r0
-               add     sp, sp, #S_PC
-               ldr     lr, [sp], #S_FRAME_SIZE - S_PC  @ Get PC and jump over PC, PSR, OLD_R0
+               ldr     lr, [sp, #S_PC]                 @ Get PC
+               add     sp, sp, #S_FRAME_SIZE
                movs    pc, lr                          @ return & move spsr_svc into cpsr
                .endm
 
@@ -348,25 +348,6 @@ irq_prio_ebsa110:
                msr     cpsr, \temp
                .endm
 
-               .macro  initialise_traps_extra
-               mrs     r0, cpsr
-               bic     r0, r0, #31
-               orr     r0, r0, #0xd3
-               msr     cpsr, r0
-               .endm
-
-
-#ifndef __ARM_ARCH_4__
-.Larm700bug:   str     lr, [r8]
-               ldr     r0, [sp, #S_PSR]                @ Get calling cpsr
-               msr     spsr, r0
-               ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
-               mov     r0, r0
-               add     sp, sp, #S_PC
-               ldr     lr, [sp], #S_FRAME_SIZE - S_PC  @ Get PC and jump over PC, PSR, OLD_R0
-               movs    pc, lr
-#endif
-
                .macro  get_current_task, rd
                mov     \rd, sp, lsr #13
                mov     \rd, \rd, lsl #13
@@ -379,231 +360,89 @@ irq_prio_ebsa110:
                adr\cond        \reg, \label
                .endm
 
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit mode).
- */
-
-vector_addrexcptn:
-               b       vector_addrexcptn
-
-/*=============================================================================
- * Undefined FIQs
- *-----------------------------------------------------------------------------
- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
- * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
- * Basically to switch modes, we *HAVE* to clobber one register...  brain
- * damage alert!  I don't think that we can execute any code in here in any
- * other mode than FIQ...  Ok you can switch to another mode, but you can't
- * get out of that mode without clobbering one register.
- */
-_unexp_fiq:    disable_fiq
-               subs    pc, lr, #4
-
-/*=============================================================================
- * Interrupt entry dispatcher
- *-----------------------------------------------------------------------------
- * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
- */
-vector_IRQ:    @
-               @ save mode specific registers
-               @
-               ldr     r13, .LCirq
-               sub     lr, lr, #4
-               str     lr, [r13]                       @ save lr_IRQ
-               mrs     lr, spsr
-               str     lr, [r13, #4]                   @ save spsr_IRQ
-               @
-               @ now branch to the relevent MODE handling routine
-               @
-               mrs     sp, cpsr                        @ switch to SVC mode
-               bic     sp, sp, #31
-               orr     sp, sp, #0x13
-               msr     spsr, sp
-               and     lr, lr, #15
-               cmp     lr, #4
-               addlts  pc, pc, lr, lsl #2              @ Changes mode and branches
-               b       __irq_invalid                   @  4 - 15
-               b       __irq_usr                       @  0  (USR_26 / USR_32)
-               b       __irq_invalid                   @  1  (FIQ_26 / FIQ_32)
-               b       __irq_invalid                   @  2  (IRQ_26 / IRQ_32)
-               b       __irq_svc                       @  3  (SVC_26 / SVC_32)
-/*
- *------------------------------------------------------------------------------------------------
- * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
- */
-.LCirq:                .word   __temp_irq
-.LCund:                .word   __temp_und
-.LCabt:                .word   __temp_abt
-
-vector_undefinstr:
-               @
-               @ save mode specific registers
-               @
-               ldr     r13, [pc, #.LCund - . - 8]
-               str     lr, [r13]
-               mrs     lr, spsr
-               str     lr, [r13, #4]
-               @
-               @ now branch to the relevent MODE handling routine
-               @
-               mrs     sp, cpsr
-               bic     sp, sp, #31
-               orr     sp, sp, #0x13
-               msr     spsr, sp
-               and     lr, lr, #15
-               cmp     lr, #4
-               addlts  pc, pc, lr, lsl #2              @ Changes mode and branches
-               b       __und_invalid                   @  4 - 15
-               b       __und_usr                       @  0 (USR_26 / USR_32)
-               b       __und_invalid                   @  1 (FIQ_26 / FIQ_32)
-               b       __und_invalid                   @  2 (IRQ_26 / IRQ_32)
-               b       __und_svc                       @  3 (SVC_26 / SVC_32)
-/*
- *------------------------------------------------------------------------------------------------
- * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
- */
-vector_prefetch:
-               @
-               @ save mode specific registers
-               @
-               sub     lr, lr, #4
-               ldr     r13, .LCabt
-               str     lr, [r13]
-               mrs     lr, spsr
-               str     lr, [r13, #4]
-               @
-               @ now branch to the relevent MODE handling routine
-               @
-               mrs     sp, cpsr
-               bic     sp, sp, #31
-               orr     sp, sp, #0x13
-               msr     spsr, sp
-               and     lr, lr, #15
-               adds    pc, pc, lr, lsl #2              @ Changes mode and branches
-               b       __pabt_invalid                  @  4 - 15
-               b       __pabt_usr                      @  0  (USR_26 / USR_32)
-               b       __pabt_invalid                  @  1  (FIQ_26 / FIQ_32)
-               b       __pabt_invalid                  @  2  (IRQ_26 / IRQ_32)
-               b       __pabt_invalid                  @  3  (SVC_26 / SVC_32)
 /*
- *------------------------------------------------------------------------------------------------
- * Data abort dispatcher - dispatches it to the correct handler for the processor mode
- *------------------------------------------------------------------------------------------------
- * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ * Invalid mode handlers
  */
-vector_data:   @
-               @ save mode specific registers
-               @
-               sub     lr, lr, #8
-               ldr     r13, .LCabt
-               str     lr, [r13]
-               mrs     lr, spsr
-               str     lr, [r13, #4]
-               @
-               @ now branch to the relevent MODE handling routine
-               @
-               mrs     sp, cpsr
-               bic     sp, sp, #31
-               orr     sp, sp, #0x13
-               msr     spsr, sp
-               and     lr, lr, #15
-               cmp     lr, #4
-               addlts  pc, pc, lr, lsl #2              @ Changes mode & branches
-               b       __dabt_invalid                  @  4 - 15
-               b       __dabt_usr                      @  0  (USR_26 / USR_32)
-               b       __dabt_invalid                  @  1  (FIQ_26 / FIQ_32)
-               b       __dabt_invalid                  @  2  (IRQ_26 / IRQ_32)
-               b       __dabt_svc                      @  3  (SVC_26 / SVC_32)
+__pabt_invalid:        sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
+               stmia   sp, {r0 - lr}                   @ Save XXX r0 - lr
+               ldr     r4, .LCabt
+               mov     r1, #BAD_PREFETCH
+               b       1f
 
-/*=============================================================================
- * Prefetch abort handler
- *-----------------------------------------------------------------------------
- */
-pabtmsg:       .ascii  "Pabt: %08lX\n\0"
-               .align
-__pabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
-               stmia   sp, {r0 - r12}                  @ Save r0 - r12
-               add     r8, sp, #S_PC
-               stmdb   r8, {sp, lr}^                   @ Save sp_usr lr_usr
+__dabt_invalid:        sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - lr}                   @ Save SVC r0 - lr [lr *should* be intact]
                ldr     r4, .LCabt
-               ldmia   r4, {r5 - r7}                   @ Get USR pc, cpsr
-               stmia   r8, {r5 - r7}                   @ Save USR pc, cpsr, old_r0
+               mov     r1, #BAD_DATA
+               b       1f
 
-               mrs     r7, cpsr                        @ Enable interrupts if they were
-               bic     r7, r7, #I_BIT                  @ previously
-               msr     cpsr, r7
-               mov     r0, r5                          @ address (pc)
-               mov     r1, sp                          @ regs
-               bl      SYMBOL_NAME(do_PrefetchAbort)   @ call abort handler
-               teq     r0, #0                          @ Does this still apply???
-               bne     ret_from_exception              @ Return from exception
-#ifdef DEBUG_UNDEF
-               adr     r0, t
-               bl      SYMBOL_NAME(printk)
-#endif
-               mov     r0, r5
-               mov     r1, sp
-               and     r2, r6, #31
-               bl      SYMBOL_NAME(do_undefinstr)
-               ldr     lr, [sp, #S_PSR]                @ Get USR cpsr
-               msr     spsr, lr
-               ldmia   sp, {r0 - pc}^                  @ Restore USR registers
+__irq_invalid: sub     sp, sp, #S_FRAME_SIZE           @ Allocate space on stack for frame
+               stmfd   sp, {r0 - lr}                   @ Save r0 - lr
+               ldr     r4, .LCirq
+               mov     r1, #BAD_IRQ
+               b       1f
 
-__pabt_invalid:        sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
-               stmia   sp, {r0 - lr}                   @ Save XXX r0 - lr
-               mov     r7, r0                          @ OLD R0
-               ldr     r4, .LCabt
-               ldmia   r4, {r5 - r7}                   @ Get XXX pc, cpsr
+__und_invalid: sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - lr}
+               ldr     r4, .LCund
+               mov     r1, #BAD_UNDEFINSTR             @ int reason
+
+1:             mov     fp, #0
+               ldmia   r4, {r5 - r7}                   @ Get XXX pc, cpsr, old_r0
                add     r4, sp, #S_PC
                stmia   r4, {r5 - r7}                   @ Save XXX pc, cpsr, old_r0
-               mov     r0, sp                          @ Prefetch aborts are definitely *not*
-               mov     r1, #BAD_PREFETCH               @ allowed in non-user modes.  We cant
-               and     r2, r6, #31                     @ recover from this problem.
+               mov     r0, sp
+               and     r2, r6, #31                     @ int mode
                b       SYMBOL_NAME(bad_mode)
 
-#ifdef DEBUG_UNDEF
-t:             .ascii "*** undef ***\r\n\0"
-               .align
-#endif
 
-/*=============================================================================
- * Data abort handler code
- *-----------------------------------------------------------------------------
+wfs_mask_data: .word   0x0e200110                      @ WFS/RFS
+               .word   0x0fef0fff
+               .word   0x0d0d0100                      @ LDF [sp]/STF [sp]
+               .word   0x0d0b0100                      @ LDF [fp]/STF [fp]
+               .word   0x0f0f0f00
+
+/* We get here if an undefined instruction happens and the floating
+ * point emulator is not present.  If the offending instruction was
+ * a WFS, we just perform a normal return as if we had emulated the
+ * operation.  This is a hack to allow some basic userland binaries
+ * to run so that the emulator module proper can be loaded. --philb
  */
-.LCprocfns:    .word   SYMBOL_NAME(processor)
+fpe_not_present:
+               adr     r10, wfs_mask_data
+               ldmia   r10, {r4, r5, r6, r7, r8}
+               ldr     r10, [sp, #S_PC]                @ Load PC
+               sub     r10, r10, #-4
+               mask_pc r10, r10
+               ldrt    r10, [r10]                      @ get instruction
+               and     r5, r10, r5
+               teq     r5, r4                          @ Is it WFS?
+               moveq   pc, r9
+               and     r5, r10, r8
+               teq     r5, r6                          @ Is it LDF/STF on sp or fp?
+               teqne   r5, r7
+               movne   pc, lr
+               tst     r10, #0x00200000                @ Does it have WB
+               moveq   pc, r9
+               and     r4, r10, #255                   @ get offset
+               and     r6, r10, #0x000f0000
+               tst     r10, #0x00800000                @ +/-
+               ldr     r5, [sp, r6, lsr #14]           @ Load reg
+               rsbeq   r4, r4, #0
+               add     r5, r5, r4, lsl #2
+               str     r5, [sp, r6, lsr #14]           @ Save reg
+               mov     pc, r9
 
-__dabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
-               stmia   sp, {r0 - r12}                  @ save r0 - r12
-               add     r3, sp, #S_PC
-               stmdb   r3, {sp, lr}^
-               ldr     r0, .LCabt
-               ldmia   r0, {r0 - r2}                   @ Get USR pc, cpsr
-               stmia   r3, {r0 - r2}                   @ Save USR pc, cpsr, old_r0
-               mov     fp, #0
-               mrs     r2, cpsr                        @ Enable interrupts if they were
-               bic     r2, r2, #I_BIT                  @ previously
-               msr     cpsr, r2
-               ldr     r2, .LCprocfns
-               mov     lr, pc
-               ldr     pc, [r2, #8]                    @ call processor specific code
-               mov     r3, sp
-               bl      SYMBOL_NAME(do_DataAbort)
-               b       ret_from_sys_call
-
-__dabt_svc:    sub     sp, sp, #S_FRAME_SIZE
+/*
+ * SVC mode handlers
+ */
+               .align  5
+__dabt_svc:    sub     sp, sp, #S_FRAME_SIZE
                stmia   sp, {r0 - r12}                  @ save r0 - r12
                ldr     r2, .LCabt
                add     r0, sp, #S_FRAME_SIZE
+               ldmia   r2, {r2 - r4}                   @ get pc, cpsr
                add     r5, sp, #S_SP
                mov     r1, lr
-               ldmia   r2, {r2 - r4}                   @ get pc, cpsr
                stmia   r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
                tst     r3, #I_BIT
                mrseq   r0, cpsr                        @ Enable interrupts if they were
@@ -619,29 +458,15 @@ __dabt_svc:       sub     sp, sp, #S_FRAME_SIZE
                msr     spsr, r0
                ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
 
-__dabt_invalid:        sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - lr}                   @ Save SVC r0 - lr [lr *should* be intact]
-               mov     r7, r0
-               ldr     r4, .LCabt
-               ldmia   r4, {r5, r6}                    @ Get SVC pc, cpsr
-               add     r4, sp, #S_PC
-               stmia   r4, {r5, r6, r7}                @ Save SVC pc, cpsr, old_r0
-               mov     r0, sp
-               mov     r1, #BAD_DATA
-               and     r2, r6, #31
-               b       SYMBOL_NAME(bad_mode)
-
-/*=============================================================================
- * Interrupt (IRQ) handler
- *-----------------------------------------------------------------------------
- */
-__irq_usr:     sub     sp, sp, #S_FRAME_SIZE
+               .align  5
+__irq_svc:     sub     sp, sp, #S_FRAME_SIZE
                stmia   sp, {r0 - r12}                  @ save r0 - r12
-               add     r8, sp, #S_PC
-               stmdb   r8, {sp, lr}^
-               ldr     r4, .LCirq
-               ldmia   r4, {r5 - r7}                   @ get saved PC, SPSR
-               stmia   r8, {r5 - r7}                   @ save pc, psr, old_r0
+               ldr     r7, .LCirq
+               add     r5, sp, #S_FRAME_SIZE
+               ldmia   r7, {r7 - r9}
+               add     r4, sp, #S_SP
+               mov     r6, lr
+               stmia   r4, {r5, r6, r7, r8, r9}        @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
 1:             get_irqnr_and_base r0, r6, r5
                movne   r1, sp
                @
@@ -649,148 +474,414 @@ __irq_usr:      sub     sp, sp, #S_FRAME_SIZE
                @
                adrsvc  ne, lr, 1b
                bne     do_IRQ
-               b       ret_with_reschedule
-
-               irq_prio_table
+               ldr     r0, [sp, #S_PSR]
+               msr     spsr, r0
+               ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
 
-__irq_svc:     sub     sp, sp, #S_FRAME_SIZE
+               .align  5
+__und_svc:     sub     sp, sp, #S_FRAME_SIZE
                stmia   sp, {r0 - r12}                  @ save r0 - r12
+               ldr     r7, .LCund
                mov     r6, lr
-               ldr     r7, .LCirq
                ldmia   r7, {r7 - r9}
                add     r5, sp, #S_FRAME_SIZE
                add     r4, sp, #S_SP
-               stmia   r4, {r5, r6, r7, r8, r9}        @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+               stmia   r4, {r5 - r9}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+
+               adrsvc  al, r9, 1f                      @ r9  = normal FP return
+               bl      call_fpe                        @ lr  = undefined instr return
+
+               mov     r0, r5                          @ unsigned long pc
+               mov     r1, sp                          @ struct pt_regs *regs
+               bl      SYMBOL_NAME(do_undefinstr)
+
+1:             ldr     lr, [sp, #S_PSR]                @ Get SVC cpsr
+               msr     spsr, lr
+               ldmia   sp, {r0 - pc}^                  @ Restore SVC registers
+
+               .align  5
+.LCirq:                .word   __temp_irq
+.LCund:                .word   __temp_und
+.LCabt:                .word   __temp_abt
+.LCprocfns:    .word   SYMBOL_NAME(processor)
+.LCfp:         .word   SYMBOL_NAME(fp_enter)
+#ifdef CONFIG_ALIGNMENT_TRAP
+.LCswi:                .word   SYMBOL_NAME(cr_alignment)
+#endif
+
+               irq_prio_table
+
+/*
+ * User mode handlers
+ */
+#ifdef DEBUG_UNDEF
+t:             .ascii "Prefetch -> undefined instruction\n\0"
+               .align
+#endif
+               .align  5
+__dabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
+               stmia   sp, {r0 - r12}                  @ save r0 - r12
+               ldr     r4, .LCabt
+               add     r3, sp, #S_PC
+               ldmia   r4, {r0 - r2}                   @ Get USR pc, cpsr
+               stmia   r3, {r0 - r2}                   @ Save USR pc, cpsr, old_r0
+               stmdb   r3, {sp, lr}^
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+               ldr     r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)]
+               mcr     p15, 0, r7, c1, c0
+#endif
+
+               mov     fp, #0
+               mrs     r2, cpsr                        @ Enable interrupts if they were
+               bic     r2, r2, #I_BIT                  @ previously
+               msr     cpsr, r2
+               ldr     r2, .LCprocfns
+               mov     lr, pc
+               ldr     pc, [r2, #8]                    @ call processor specific code
+               mov     r3, sp
+               adrsvc  al, lr, ret_from_sys_call
+               b       SYMBOL_NAME(do_DataAbort)
+
+               .align  5
+__irq_usr:     sub     sp, sp, #S_FRAME_SIZE
+               stmia   sp, {r0 - r12}                  @ save r0 - r12
+               ldr     r4, .LCirq
+               add     r8, sp, #S_PC
+               ldmia   r4, {r5 - r7}                   @ get saved PC, SPSR
+               stmia   r8, {r5 - r7}                   @ save pc, psr, old_r0
+               stmdb   r8, {sp, lr}^
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+               ldr     r7, [r4, #OFF_CR_ALIGNMENT(__temp_irq)]
+               mcr     p15, 0, r7, c1, c0
+#endif
+
+               mov     fp, #0
 1:             get_irqnr_and_base r0, r6, r5
                movne   r1, sp
+               adrsvc  ne, lr, 1b
                @
                @ routine called with r0 = irq number, r1 = struct pt_regs *
                @
-               adrsvc  ne, lr, 1b
                bne     do_IRQ
-               ldr     r0, [sp, #S_PSR]
-               msr     spsr, r0
-               ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
-
-__irq_invalid: sub     sp, sp, #S_FRAME_SIZE   @ Allocate space on stack for frame
-               stmfd   sp, {r0 - lr}           @ Save r0 - lr
-               mov     r7, #-1
-               ldr     r4, .LCirq
-               ldmia   r4, {r5, r6}            @ get saved pc, psr
-               add     r4, sp, #S_PC
-               stmia   r4, {r5, r6, r7}
-               mov     fp, #0
-               mov     r0, sp
-               mov     r1, #BAD_IRQ
-               b       SYMBOL_NAME(bad_mode)
-
-/*=============================================================================
- * Undefined instruction handler
- *-----------------------------------------------------------------------------
- * Handles floating point instructions
- */
-.LC2:          .word   SYMBOL_NAME(fp_enter)
+               mov     r4, #0
+               b       ret_with_reschedule
 
+               .align  5
 __und_usr:     sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
                stmia   sp, {r0 - r12}                  @ Save r0 - r12
-               add     r8, sp, #S_PC
-               stmdb   r8, {sp, lr}^                   @ Save user r0 - r12
                ldr     r4, .LCund
+               add     r8, sp, #S_PC
                ldmia   r4, {r5 - r7}
                stmia   r8, {r5 - r7}                   @ Save USR pc, cpsr, old_r0
-               mov     fp, #0
+               stmdb   r8, {sp, lr}^                   @ Save user r0 - r12
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+               ldr     r7, [r4, #OFF_CR_ALIGNMENT(__temp_und)]
+               mcr     p15, 0, r7, c1, c0
+#endif
 
-               adrsvc  al, r9, ret_from_exception      @ r9  = normal FP return
+               mov     fp, #0
+               adrsvc  al, r9, ret_from_sys_call       @ r9  = normal FP return
                adrsvc  al, lr, fpundefinstr            @ lr  = undefined instr return
 
-1:             get_current_task r10
+call_fpe:      get_current_task r10
                mov     r8, #1
                strb    r8, [r10, #TSK_USED_MATH]       @ set current->used_math
+               ldr     r4, .LCfp
                add     r10, r10, #TSS_FPESAVE          @ r10 = workspace
-               ldr     r4, .LC2
                ldr     pc, [r4]                        @ Call FP module USR entry point
 
-__und_svc:     sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - r12}                  @ save r0 - r12
-               mov     r6, lr
-               ldr     r7, .LCund
-               ldmia   r7, {r7 - r9}
-               add     r5, sp, #S_FRAME_SIZE
-               add     r4, sp, #S_SP
-               stmia   r4, {r5 - r9}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-
-               adrsvc  al, r9, 3f                      @ r9  = normal FP return
-               bl      1b                              @ lr  = undefined instr return
-
-               mov     r0, r5                          @ unsigned long pc
-               mov     r1, sp                          @ struct pt_regs *regs
-               bl      SYMBOL_NAME(do_undefinstr)
-
-3:             ldr     lr, [sp, #S_PSR]                @ Get SVC cpsr
-               msr     spsr, lr
-               ldmia   sp, {r0 - pc}^                  @ Restore SVC registers
-
 fpundefinstr:  mov     r0, lr
                mov     r1, sp
                mrs     r4, cpsr                        @ Enable interrupts
                bic     r4, r4, #I_BIT
                msr     cpsr, r4
-               adrsvc  al, lr, ret_from_exception
+               adrsvc  al, lr, ret_from_sys_call
                b       SYMBOL_NAME(do_undefinstr)
 
-__und_invalid: sub     sp, sp, #S_FRAME_SIZE
-               stmia   sp, {r0 - lr}
-               mov     r7, r0
-               ldr     r4, .LCund
-               ldmia   r4, {r5, r6}                    @ Get UND/IRQ/FIQ/ABT pc, cpsr
-               add     r4, sp, #S_PC
-               stmia   r4, {r5, r6, r7}                @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
-               mov     r0, sp                          @ struct pt_regs *regs
-               mov     r1, #BAD_UNDEFINSTR             @ int reason
-               and     r2, r6, #31                     @ int mode
-               b       SYMBOL_NAME(bad_mode)           @ Does not ever return...
+               .align  5
+__pabt_usr:    sub     sp, sp, #S_FRAME_SIZE           @ Allocate frame size in one go
+               stmia   sp, {r0 - r12}                  @ Save r0 - r12
+               ldr     r4, .LCabt
+               add     r8, sp, #S_PC
+               ldmia   r4, {r5 - r7}                   @ Get USR pc, cpsr
+               stmia   r8, {r5 - r7}                   @ Save USR pc, cpsr, old_r0
+               stmdb   r8, {sp, lr}^                   @ Save sp_usr lr_usr
 
-/* We get here if an undefined instruction happens and the floating
- * point emulator is not present.  If the offending instruction was
- * a WFS, we just perform a normal return as if we had emulated the
- * operation.  This is a hack to allow some basic userland binaries
- * to run so that the emulator module proper can be loaded. --philb
- */
-fpe_not_present:
-               adr     r10, wfs_mask_data
-               ldmia   r10, {r4, r5, r6, r7, r8}
-               ldr     r10, [sp, #S_PC]                @ Load PC
-               sub     r10, r10, #4
-               mask_pc r10, r10
-               ldrt    r10, [r10]                      @ get instruction
-               and     r5, r10, r5
-               teq     r5, r4                          @ Is it WFS?
-               moveq   pc, r9
-               and     r5, r10, r8
-               teq     r5, r6                          @ Is it LDF/STF on sp or fp?
-               teqne   r5, r7
-               movne   pc, lr
-               tst     r10, #0x00200000                @ Does it have WB
-               moveq   pc, r9
-               and     r4, r10, #255                   @ get offset
-               and     r6, r10, #0x000f0000
-               tst     r10, #0x00800000                @ +/-
-               rsbeq   r4, r4, #0
-               ldr     r5, [sp, r6, lsr #14]           @ Load reg
-               add     r5, r5, r4, lsl #2
-               str     r5, [sp, r6, lsr #14]           @ Save reg
-               mov     pc, r9
+#ifdef CONFIG_ALIGNMENT_TRAP
+               ldr     r7, [r4, #OFF_CR_ALIGNMENT(__temp_abt)]
+               mcr     p15, 0, r7, c1, c0
+#endif
 
-wfs_mask_data: .word   0x0e200110                      @ WFS
-               .word   0x0fff0fff
-               .word   0x0d0d0100                      @ LDF [sp]/STF [sp]
-               .word   0x0d0b0100                      @ LDF [fp]/STF [fp]
-               .word   0x0f0f0f00
+               mov     fp, #0
+               mrs     r7, cpsr                        @ Enable interrupts if they were
+               bic     r7, r7, #I_BIT                  @ previously
+               msr     cpsr, r7
+               mov     r0, r5                          @ address (pc)
+               mov     r1, sp                          @ regs
+               bl      SYMBOL_NAME(do_PrefetchAbort)   @ call abort handler
+               teq     r0, #0                          @ Does this still apply???
+               bne     ret_from_sys_call               @ Return from exception
+#ifdef DEBUG_UNDEF
+               adr     r0, t
+               bl      SYMBOL_NAME(printk)
+#endif
+               mov     r0, r5
+               mov     r1, sp
+               and     r2, r6, #31
+               bl      SYMBOL_NAME(do_undefinstr)
+               ldr     lr, [sp, #S_PSR]                @ Get USR cpsr
+               msr     spsr, lr
+               ldmia   sp, {r0 - pc}^                  @ Restore USR registers
 
 #include "entry-common.S"
 
+               .text
+
+#ifndef __ARM_ARCH_4__
+.Larm700bug:   ldr     r0, [sp, #S_PSR]                @ Get calling cpsr
+               str     lr, [r8]
+               msr     spsr, r0
+               ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
+               mov     r0, r0
+               ldr     lr, [sp, #S_PC]                 @ Get PC
+               add     sp, sp, #S_FRAME_SIZE
+               movs    pc, lr
+#endif
+
+               .section ".text.init",#alloc,#execinstr
+/*
+ * Vector stubs.  NOTE that we only align 'vector_IRQ' to a cache line boundary,
+ * and we rely on each stub being exactly 48 (1.5 cache lines) in size.  This
+ * means that we only ever load two cache lines for this code, or one if we're
+ * lucky.  We also copy this code to 0x200 so that we can use branches in the
+ * vectors, rather than ldr's.
+ */
+               .align  5
+__stubs_start:
+/*
+ * Interrupt dispatcher
+ * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
+ */
+vector_IRQ:    @
+               @ save mode specific registers
+               @
+               ldr     r13, .LCsirq
+               sub     lr, lr, #4
+               str     lr, [r13]                       @ save lr_IRQ
+               mrs     lr, spsr
+               str     lr, [r13, #4]                   @ save spsr_IRQ
+               @
+               @ now branch to the relevent MODE handling routine
+               @
+               bic     r13, lr, #63
+               orr     r13, r13, #0x93
+               msr     spsr, r13                       @ switch to SVC_32 mode
+
+               and     lr, lr, #15
+               adr     r13, .LCtab_irq
+               ldr     lr, [r13, lr, lsl #2]
+               movs    pc, lr                          @ Changes mode and branches
+/*
+ * Data abort dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ */
+vector_data:   @
+               @ save mode specific registers
+               @
+               ldr     r13, .LCsabt
+               sub     lr, lr, #8
+               str     lr, [r13]
+               mrs     lr, spsr
+               str     lr, [r13, #4]
+               @
+               @ now branch to the relevent MODE handling routine
+               @
+               bic     r13, lr, #63
+               orr     r13, r13, #0x93
+               msr     spsr, r13                       @ switch to SVC_32 mode
+
+               and     lr, lr, #15
+               adr     r13, .LCtab_dabt
+               ldr     lr, [r13, lr, lsl #2]
+               movs    pc, lr                          @ Changes mode and branches
+
+/*
+ * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
+ */
+vector_prefetch:
+               @
+               @ save mode specific registers
+               @
+               ldr     r13, .LCsabt
+               sub     lr, lr, #4
+               str     lr, [r13]                       @ save lr_ABT
+               mrs     lr, spsr
+               str     lr, [r13, #4]                   @ save spsr_ABT
+               @
+               @ now branch to the relevent MODE handling routine
+               @
+               bic     r13, lr, #63
+               orr     r13, r13, #0x93
+               msr     spsr, r13                       @ switch to SVC_32 mode
+
+               ands    lr, lr, #15
+               ldreq   lr, .LCtab_pabt
+               ldrne   lr, .LCtab_pabt + 4
+               movs    pc, lr
+
+/*
+ * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode
+ * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
+ */
+vector_undefinstr:
+               @
+               @ save mode specific registers
+               @
+               ldr     r13, .LCsund
+               str     lr, [r13]                       @ save lr_UND
+               mrs     lr, spsr
+               str     lr, [r13, #4]                   @ save spsr_UND
+               @
+               @ now branch to the relevent MODE handling routine
+               @
+               bic     r13, lr, #63
+               orr     r13, r13, #0x93
+               msr     spsr, r13                       @ switch to SVC_32 mode
+
+               and     lr, lr, #15
+               adr     r13, .LCtab_und
+               ldr     lr, [r13, lr, lsl #2]
+               movs    pc, lr                          @ Changes mode and branches
+
+/*=============================================================================
+ * Undefined FIQs
+ *-----------------------------------------------------------------------------
+ * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
+ * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
+ * Basically to switch modes, we *HAVE* to clobber one register...  brain
+ * damage alert!  I don't think that we can execute any code in here in any
+ * other mode than FIQ...  Ok you can switch to another mode, but you can't
+ * get out of that mode without clobbering one register.
+ */
+vector_FIQ:    disable_fiq
+               subs    pc, lr, #4
+
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+               b       vector_addrexcptn
+
+/*
+ * We group all the following data together to optimise
+ * for CPUs with separate I & D caches.
+ */
+               .align  5
+
+.LCtab_irq:    .word   __irq_usr                       @  0  (USR_26 / USR_32)
+               .word   __irq_invalid                   @  1  (FIQ_26 / FIQ_32)
+               .word   __irq_invalid                   @  2  (IRQ_26 / IRQ_32)
+               .word   __irq_svc                       @  3  (SVC_26 / SVC_32)
+               .word   __irq_invalid                   @  4
+               .word   __irq_invalid                   @  5
+               .word   __irq_invalid                   @  6
+               .word   __irq_invalid                   @  7
+               .word   __irq_invalid                   @  8
+               .word   __irq_invalid                   @  9
+               .word   __irq_invalid                   @  a
+               .word   __irq_invalid                   @  b
+               .word   __irq_invalid                   @  c
+               .word   __irq_invalid                   @  d
+               .word   __irq_invalid                   @  e
+               .word   __irq_invalid                   @  f
+
+.LCtab_und:    .word   __und_usr                       @  0 (USR_26 / USR_32)
+               .word   __und_invalid                   @  1 (FIQ_26 / FIQ_32)
+               .word   __und_invalid                   @  2 (IRQ_26 / IRQ_32)
+               .word   __und_svc                       @  3 (SVC_26 / SVC_32)
+               .word   __und_invalid                   @  4
+               .word   __und_invalid                   @  5
+               .word   __und_invalid                   @  6
+               .word   __und_invalid                   @  7
+               .word   __und_invalid                   @  8
+               .word   __und_invalid                   @  9
+               .word   __und_invalid                   @  a
+               .word   __und_invalid                   @  b
+               .word   __und_invalid                   @  c
+               .word   __und_invalid                   @  d
+               .word   __und_invalid                   @  e
+               .word   __und_invalid                   @  f
+
+.LCtab_dabt:   .word   __dabt_usr                      @  0  (USR_26 / USR_32)
+               .word   __dabt_invalid                  @  1  (FIQ_26 / FIQ_32)
+               .word   __dabt_invalid                  @  2  (IRQ_26 / IRQ_32)
+               .word   __dabt_svc                      @  3  (SVC_26 / SVC_32)
+               .word   __dabt_invalid                  @  4
+               .word   __dabt_invalid                  @  5
+               .word   __dabt_invalid                  @  6
+               .word   __dabt_invalid                  @  7
+               .word   __dabt_invalid                  @  8
+               .word   __dabt_invalid                  @  9
+               .word   __dabt_invalid                  @  a
+               .word   __dabt_invalid                  @  b
+               .word   __dabt_invalid                  @  c
+               .word   __dabt_invalid                  @  d
+               .word   __dabt_invalid                  @  e
+               .word   __dabt_invalid                  @  f
+
+.LCtab_pabt:   .word   __pabt_usr
+               .word   __pabt_invalid
+
+.LCvswi:       .word   vector_swi
+
+.LCsirq:       .word   __temp_irq
+.LCsund:       .word   __temp_und
+.LCsabt:       .word   __temp_abt
+
+__stubs_end:
+
+               .equ    __real_stubs_start, .LCvectors + 0x200
+
+.LCvectors:    swi     SYS_ERROR0
+               b       __real_stubs_start + (vector_undefinstr - __stubs_start)
+               ldr     pc, __real_stubs_start + (.LCvswi - __stubs_start)
+               b       __real_stubs_start + (vector_prefetch - __stubs_start)
+               b       __real_stubs_start + (vector_data - __stubs_start)
+               b       __real_stubs_start + (vector_addrexcptn - __stubs_start)
+               b       __real_stubs_start + (vector_IRQ - __stubs_start)
+               b       __real_stubs_start + (vector_FIQ - __stubs_start)
+
+ENTRY(trap_init)
+               stmfd   sp!, {r4 - r6, lr}
+
+               adr     r1, .LCvectors                  @ set up the vectors
+               mov     r0, #0
+               ldmia   r1, {r1, r2, r3, r4, r5, r6, ip, lr}
+               stmia   r0, {r1, r2, r3, r4, r5, r6, ip, lr}
+
+               add     r2, r0, #0x200
+               adr     r0, __stubs_start               @ copy stubs to 0x200
+               adr     r1, __stubs_end
+1:             ldr     r3, [r0], #4
+               str     r3, [r2], #4
+               cmp     r0, r1
+               blt     1b
+               LOADREGS(fd, sp!, {r4 - r6, pc})
+
                .data
 
+/*
+ * Do not reorder these, and do not insert extra data between...
+ */
+
 __temp_irq:    .word   0                               @ saved lr_irq
                .word   0                               @ saved spsr_irq
                .word   -1                              @ old_r0
@@ -800,3 +891,10 @@ __temp_und:        .word   0                               @ Saved lr_und
 __temp_abt:    .word   0                               @ Saved lr_abt
                .word   0                               @ Saved spsr_abt
                .word   -1                              @ old_r0
+
+               .globl  SYMBOL_NAME(cr_alignment)
+               .globl  SYMBOL_NAME(cr_no_alignment)
+SYMBOL_NAME(cr_alignment):
+               .space  4
+SYMBOL_NAME(cr_no_alignment):
+               .space  4
index c77c0ea5142c3883e6f081837cbeb2b14fb2d2c8..2fc0fdddc3e6ecdc220797f8fdf6e802c10fecd1 100644 (file)
@@ -1,51 +1,54 @@
 /*============================================================================
  * All exits to user mode from the kernel go through this code.
  */
-
-#include <linux/config.h>
-
                .globl  ret_from_sys_call
 
-ret_from_exception:
-               adr     r0, 1f
-               ldmia   r0, {r0, r1}
+               .align  5
+fast_syscall_return:
+               str     r0, [sp, #S_R0 + 4]             @ returned r0
+slow_syscall_return:
+               add     sp, sp, #4
+ret_from_sys_call:
+               adr     r0, bh_data
+               ldmia   r0, {r0, r4}
                ldr     r0, [r0]
-               ldr     r1, [r1]
+               ldr     r1, [r4]
                tst     r0, r1
                blne    SYMBOL_NAME(do_bottom_half)
-ret_from_intr: ldr     r0, [sp, #S_PSR]
-               tst     r0, #3
-               beq     ret_with_reschedule
-               b       ret_from_all
+ret_with_reschedule:
+               get_current_task r1             @ check for scheduling
+               ldr     r0, [r1, #TSK_NEED_RESCHED]
+               teq     r0, #0
+               bne     ret_reschedule
+               ldr     r1, [r1, #TSK_SIGPENDING]
+               teq     r1, #0                  @ check for signals
+               bne     ret_signal
+
+ret_from_all:  restore_user_regs
 
 ret_signal:    mov     r1, sp
                adrsvc  al, lr, ret_from_all
+               mov     r2, r4
                b       SYMBOL_NAME(do_signal)
 
-2:             bl      SYMBOL_NAME(schedule)
+ret_reschedule:        adrsvc  al, lr, ret_with_reschedule
+               b       SYMBOL_NAME(schedule)
 
-ret_from_sys_call:
-               adr     r0, 1f
+               .globl  ret_from_exception
+ret_from_exception:
+               adr     r0, bh_data
                ldmia   r0, {r0, r1}
                ldr     r0, [r0]
                ldr     r1, [r1]
+               mov     r4, #0
                tst     r0, r1
-               adrsvc  ne, lr, ret_from_intr
-               bne     SYMBOL_NAME(do_bottom_half)
-
-ret_with_reschedule:
-               get_current_task r1
-               ldr     r0, [r1, #TSK_NEED_RESCHED]
-               teq     r0, #0
-               bne     2b
-               ldr     r1, [r1, #TSK_SIGPENDING]
-               teq     r1, #0
-               bne     ret_signal
-
-ret_from_all:  restore_user_regs
+               blne    SYMBOL_NAME(do_bottom_half)
+               ldr     r0, [sp, #S_PSR]
+               tst     r0, #3                  @ returning to user mode?
+               beq     ret_with_reschedule
+               b       ret_from_all
 
-1:             .word   SYMBOL_NAME(bh_mask)
-               .word   SYMBOL_NAME(bh_active)
+#include "calls.S"
 
 /*=============================================================================
  * SWI handler
@@ -57,84 +60,65 @@ ret_from_all:       restore_user_regs
  * too worried.
  */
 
-#include "calls.S"
-
+               .align  5
 vector_swi:    save_user_regs
-               mov     fp, #0
                mask_pc lr, lr
-               ldr     r6, [lr, #-4]!          @ get SWI instruction
+               mov     fp, #0
+               ldr     r6, [lr, #-4]           @ get SWI instruction
                arm700_bug_check r6, r7
+#ifdef CONFIG_ALIGNMENT_TRAP
+               ldr     r7, .LCswi
+               ldr     r7, [r7]
+               mcr     p15, 0, r7, c1, c0
+#endif
                enable_irqs r7
-               
+
+               str     r4, [sp, #-4]!          @ new style: (r0 = arg1, r4 = arg5)
+               adrsvc  al, lr, fast_syscall_return
+
                bic     r6, r6, #0xff000000     @ mask off SWI op-code
                eor     r6, r6, #OS_NUMBER<<20  @ check OS number
                cmp     r6, #NR_syscalls        @ check upper syscall limit
                bcs     2f
 
-               get_current_task r5
-               ldr     ip, [r5, #TSK_FLAGS]    @ check for syscall tracing
+               get_current_task r7
+               ldr     ip, [r7, #TSK_FLAGS]    @ check for syscall tracing
+               adr     r5, SYMBOL_NAME(sys_call_table)
                tst     ip, #PF_TRACESYS
-               bne     1f
+               ldreq   pc, [r5, r6, lsl #2]    @ call sys routine
 
-               adr     ip, SYMBOL_NAME(sys_call_table)
-               str     r4, [sp, #-4]!          @ new style: (r0 = arg1, r5 = arg5)
-               mov     lr, pc
-               ldr     pc, [ip, r6, lsl #2]    @ call sys routine
-               add     sp, sp, #4
-               str     r0, [sp, #S_R0]         @ returned r0
-               b       ret_from_sys_call
-
-1:             ldr     r7, [sp, #S_IP]         @ save old IP
+               ldr     r7, [sp, #S_IP + 4]     @ save old IP
                mov     r0, #0
-               str     r0, [sp, #S_IP]         @ trace entry [IP = 0]
+               str     r0, [sp, #S_IP + 4]     @ trace entry [IP = 0]
                bl      SYMBOL_NAME(syscall_trace)
-               str     r7, [sp, #S_IP]
-               ldmia   sp, {r0 - r3}           @ have to reload r0 - r3
-               adr     ip, SYMBOL_NAME(sys_call_table)
-               str     r4, [sp, #-4]!          @ new style: (r0 = arg1, r5 = arg5)
+               str     r7, [sp, #S_IP + 4]
+
+               ldmib   sp, {r0 - r3}           @ have to reload r0 - r3
                mov     lr, pc
-               ldr     pc, [ip, r6, lsl #2]    @ call sys routine
-               add     sp, sp, #4
-               str     r0, [sp, #S_R0]         @ returned r0
+               ldr     pc, [r5, r6, lsl #2]    @ call sys routine
+               str     r0, [sp, #S_R0 + 4]     @ returned r0
+
                mov     r0, #1
-               str     r0, [sp, #S_IP]         @ trace exit [IP = 1]
+               str     r0, [sp, #S_IP + 4]     @ trace exit [IP = 1]
                bl      SYMBOL_NAME(syscall_trace)
-               str     r7, [sp, #S_IP]
-               b       ret_from_sys_call
+               str     r7, [sp, #S_IP + 4]
+               b       slow_syscall_return
 
-2:             tst     r6, #0x00f00000         @ is it a Unix SWI?
+2:             add     r1, sp, #4
+               tst     r6, #0x00f00000         @ is it a Unix SWI?
                bne     3f
-               cmp     r6, #(KSWI_SYS_BASE - KSWI_BASE)
-               bcc     4f                      @ not private func
-               bic     r0, r6, #0x000f0000
-               mov     r1, sp
-               bl      SYMBOL_NAME(arm_syscall)
-               b       ret_from_sys_call
-
-3:             eor     r0, r6, #OS_NUMBER<<20  @ Put OS number back
-               mov     r1, sp
-               bl      SYMBOL_NAME(deferred)
-               ldmfd   sp, {r0 - r3}
-               b       ret_from_sys_call
-
-4:             bl      SYMBOL_NAME(sys_ni_syscall)
-               str     r0, [sp, #0]            @ returned r0
-               b       ret_from_sys_call
+               subs    r0, r6, #(KSWI_SYS_BASE - KSWI_BASE)
+               bcs     SYMBOL_NAME(arm_syscall)
+               b       SYMBOL_NAME(sys_ni_syscall) @ not private func
 
-@ r0 = syscall number
-@ r1 = syscall r0
-@ r5 = syscall r4
-@ ip = syscall table
-SYMBOL_NAME(sys_syscall):
-               mov     r6, r0
-               eor     r6, r6, #OS_NUMBER << 20
-               cmp     r6, #NR_syscalls                @ check range
-               movgt   r0, #-ENOSYS
-               movgt   pc, lr
-               add     sp, sp, #4                      @ take of the save of our r4
-               ldmib   sp, {r0 - r4}                   @ get our args
-               str     r4, [sp, #-4]!                  @ Put our arg on the stack
-               ldr     pc, [ip, r6, lsl #2]
+3:             eor     r0, r6, #OS_NUMBER <<20 @ Put OS number back
+               adrsvc  al, lr, slow_syscall_return
+               b       SYMBOL_NAME(deferred)
+
+               .align  5
+
+bh_data:       .word   SYMBOL_NAME(bh_mask)
+               .word   SYMBOL_NAME(bh_active)
 
 ENTRY(sys_call_table)
 #include "calls.S"
@@ -142,10 +126,25 @@ ENTRY(sys_call_table)
 /*============================================================================
  * Special system call wrappers
  */
+@ r0 = syscall number
+@ r5 = syscall table
+SYMBOL_NAME(sys_syscall):
+               eor     r6, r0, #OS_NUMBER << 20
+               cmp     r6, #NR_syscalls        @ check range
+               ldmleib sp, {r0 - r4}           @ get our args
+               strle   r4, [sp]                @ Put our arg on the stack
+               ldrle   pc, [r5, r6, lsl #2]
+               mov     r0, #-ENOSYS
+               mov     pc, lr
+
 sys_fork_wrapper:
                add     r0, sp, #4
                b       SYMBOL_NAME(sys_fork)
 
+sys_vfork_wrapper:
+               add     r0, sp, #4
+               b       SYMBOL_NAME(sys_vfork)
+
 sys_execve_wrapper:
                add     r3, sp, #4
                b       SYMBOL_NAME(sys_execve)
@@ -192,99 +191,6 @@ sys_sigaltstack_wrapper:
                ldr     r2, [sp, #4 + S_SP]
                b       do_sigaltstack
 
-/*
- *=============================================================================
- *             Low-level interface code
- *-----------------------------------------------------------------------------
- *             Trap initialisation
- *-----------------------------------------------------------------------------
- *
- * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
- * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
- * some excess cycles).
- *
- * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
- * (the kernel).
- * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
- * the actual address to jump to.
- */
-
-               .section ".text.init",#alloc,#execinstr
-
-#if defined(CONFIG_CPU_32)
-/*
- * these go into 0x00
- */
-.Lbranches:    swi     SYS_ERROR0
-               ldr     pc, .Lbranches + 0xe4
-               ldr     pc, .Lbranches + 0xe8
-               ldr     pc, .Lbranches + 0xec
-               ldr     pc, .Lbranches + 0xf0
-               ldr     pc, .Lbranches + 0xf4
-               ldr     pc, .Lbranches + 0xf8
-               ldr     pc, .Lbranches + 0xfc
-/*
- * this is put into 0xe4 and above
- */
-.Ljump_addresses:
-               .word   vector_undefinstr       @ 0xe4
-               .word   vector_swi              @ 0xe8
-               .word   vector_prefetch         @ 0xec
-               .word   vector_data             @ 0xf0
-               .word   vector_addrexcptn       @ 0xf4
-               .word   vector_IRQ              @ 0xf8
-               .word   _unexp_fiq              @ 0xfc
-/*
- * initialise the trap system
- */
-ENTRY(trap_init)
-               stmfd   sp!, {r4 - r7, lr}
-               initialise_traps_extra
-               mov     r0, #0xe4
-               adr     r1, .Ljump_addresses
-               ldmia   r1, {r1 - r7}
-               stmia   r0, {r1 - r7}
-               mov     r0, #0
-               adr     r1, .Lbranches
-               ldmia   r1, {r1 - r7}
-               stmia   r0, {r1 - r7}
-               LOADREGS(fd, sp!, {r4 - r7, pc})
-#elif defined(CONFIG_CPU_26)
-.Ljump_addresses:
-               swi     SYS_ERROR0
-               .word   vector_undefinstr       - 12
-               .word   vector_swi              - 16
-               .word   vector_prefetch         - 20
-               .word   vector_data             - 24
-               .word   vector_addrexcptn       - 28
-               .word   vector_IRQ              - 32
-               .word   _unexp_fiq              - 36
-               b       . + 8
-/*
- * initialise the trap system
- */
-ENTRY(trap_init)
-               stmfd   sp!, {r4 - r7, lr}
-               adr     r1, .Ljump_addresses
-               ldmia   r1, {r1 - r7, ip, lr}
-               orr     r2, lr, r2, lsr #2
-               orr     r3, lr, r3, lsr #2
-               orr     r4, lr, r4, lsr #2
-               orr     r5, lr, r5, lsr #2
-               orr     r6, lr, r6, lsr #2
-               orr     r7, lr, r7, lsr #2
-               orr     ip, lr, ip, lsr #2
-               mov     r0, #0
-               stmia   r0, {r1 - r7, ip}
-               ldmfd   sp!, {r4 - r7, pc}^
-#endif
-
-               .previous
-
-/*============================================================================
- * FP support
- */
-
                .data
 
 ENTRY(fp_enter)
index a5da15c7fc673d27ff2e74b94244c15a2978c19c..e3e87469fa5133dbc143cbcbb8f083af1a316f2c 100644 (file)
@@ -2,6 +2,8 @@
  *  linux/arch/arm/kernel/fiq.c
  *
  *  Copyright (C) 1998 Russell King
+ *  Copyright (C) 1998, 1999 Phil Blundell
+ *
  *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
  *
  *  FIQ support re-written by Russell King to be more generic
@@ -78,7 +80,7 @@ int fiq_def_op(void *ref, int relinquish)
                unprotect_page_0();
                *(unsigned long *)FIQ_VECTOR = no_fiq_insn;
                protect_page_0();
-               __flush_entry_to_ram(FIQ_VECTOR);
+               flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4);
        }
 
        return 0;
@@ -106,28 +108,77 @@ void set_fiq_handler(void *start, unsigned int length)
        memcpy((void *)FIQ_VECTOR, start, length);
 
        protect_page_0();
-#ifdef CONFIG_CPU_32
-       processor.u.armv3v4._flush_cache_area(FIQ_VECTOR, FIQ_VECTOR + length, 1);
-#endif
+       flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length);
 }
 
+/*
+ * Taking an interrupt in FIQ mode is death, so both these functions
+ * disable irqs for the duration. 
+ */
 void set_fiq_regs(struct pt_regs *regs)
 {
-       /* not yet -
-        * this is temporary to get the floppy working
-        * again on RiscPC.  It *will* become more
-        * generic.
-        */
-#ifdef CONFIG_ARCH_ACORN
-       extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
-                                            unsigned long port);
-       floppy_fiqsetup(regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
+       register unsigned long tmp, tmp2;
+       __asm__ volatile (
+#ifdef CONFIG_CPU_26
+       "mov    %0, pc
+       bic     %1, %0, #0x3
+       orr     %1, %1, #0x0c000001
+       teqp    %1, #0          @ select FIQ mode
+       mov     r0, r0
+       ldmia   %2, {r8 - r14}
+       teqp    %0, #0          @ return to SVC mode
+       mov     r0, r0"
 #endif
+#ifdef CONFIG_CPU_32
+       "mrs    %0, cpsr
+       bic     %1, %0, #0xf
+       orr     %1, %1, #0xc1
+       msr     cpsr, %1        @ select FIQ mode
+       mov     r0, r0
+       ldmia   %2, {r8 - r14}
+       msr     cpsr, %0        @ return to SVC mode
+       mov     r0, r0"
+#endif
+       : "=r" (tmp), "=r" (tmp2)
+       : "r" (&regs->ARM_r8)
+       /* These registers aren't modified by the above code in a way
+          visible to the compiler, but we mark them as clobbers anyway
+          so that GCC won't put any of the input or output operands in
+          them.  */
+       : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
 }
 
 void get_fiq_regs(struct pt_regs *regs)
 {
-       /* not yet */
+       register unsigned long tmp, tmp2;
+       __asm__ volatile (
+#ifdef CONFIG_CPU_26
+       "mov    %0, pc
+       bic     %1, %0, #0x3
+       orr     %1, %1, #0x0c000001
+       teqp    %1, #0          @ select FIQ mode
+       mov     r0, r0
+       stmia   %2, {r8 - r14}
+       teqp    %0, #0          @ return to SVC mode
+       mov     r0, r0"
+#endif
+#ifdef CONFIG_CPU_32
+       "mrs    %0, cpsr
+       bic     %1, %0, #0xf
+       orr     %1, %1, #0xc1
+       msr     cpsr, %1        @ select FIQ mode
+       mov     r0, r0
+       stmia   %2, {r8 - r14}
+       msr     cpsr, %0        @ return to SVC mode
+       mov     r0, r0"
+#endif
+       : "=r" (tmp), "=r" (tmp2)
+       : "r" (&regs->ARM_r8)
+       /* These registers aren't modified by the above code in a way
+          visible to the compiler, but we mark them as clobbers anyway
+          so that GCC won't put any of the input or output operands in
+          them.  */
+       : "r8", "r9", "r10", "r11", "r12", "r13", "r14");
 }
 
 int claim_fiq(struct fiq_handler *f)
index cd4be86cb2fb4765738d0375e3c1f50c72ceeb84..2e13f08182b7db51a8e22d4f3f09fc4b654bed16 100644 (file)
@@ -7,13 +7,21 @@
  */
 #include <linux/config.h>
 #include <linux/linkage.h>
+#include <asm/hardware.h>
+#include <asm/dec21285.h>
+
+               .globl  SYMBOL_NAME(swapper_pg_dir)
+               .equ    SYMBOL_NAME(swapper_pg_dir),    TEXTADDR - 0x4000
+
+               .section ".text.init",#alloc,#execinstr
+ENTRY(stext)
+ENTRY(_stext)
 
-#ifndef CONFIG_ARCH_VNC
 #if (TEXTADDR & 0xffff) != 0x8000
 #error TEXTADDR must start at 0xXXXX8000
 #endif
-#else
-               .text
+
+#ifdef CONFIG_ARCH_NETWINDER
                mov     r0, r0
                mov     r0, r0
                mov     r0, r0
                mov     r0, r0
                mov     r0, r0
                mov     r0, r0
+
+               adr     r2, 1f
+               ldmdb   r2, {r7, r8}
+               and     r3, r2, #0x0000c000
+               teq     r3, #0x00008000
+               beq     __entry
+               bic     r3, r2, #0xc000
+               orr     r3, r3, #0x8000
+               mov     r0, r3
+               mov     r4, #32
+               sub     r5, r8, r7
+               b       1f
+
+               .word   _stext
+               .word   _end
+
+1:             ldmia   r2!, {r6, r7, r8, r9}
+               stmia   r3!, {r6, r7, r8, r9}
+               subs    r4, r4, #16
+               bcs     1b
+               movs    r4, r5
+               mov     r5, #0
+               movne   pc, r0
+
                mov     r0, #0
                mov     r1, #5
 #endif
 
-#define DEBUG
-
-               .globl  SYMBOL_NAME(swapper_pg_dir)
-               .equ    SYMBOL_NAME(swapper_pg_dir),    TEXTADDR - 0x4000
-
-               .text
 /*
  * Entry point and restart point.  Entry *must* be called with r0 == 0,
  * MMU off.  Note! These should be unique!!! Please read Documentation/ARM-README
  *  r1 = 5 -> Corel Netwinder
  *  r1 = 6 -> CATS
  *  r1 = 7 -> tbox
+ *  r1 = 8 -> SA110/21285 as co-processor
  */
 
-ENTRY(stext)
-ENTRY(_stext)
 __entry:       teq     r0, #0                                  @ check for illegal entry...
                bne     .Lerror                                 @ loop indefinitely
-               cmp     r1, #8                                  @ Unknown machine architecture
+               cmp     r1, #9                                  @ Unknown machine architecture
                bge     .Lerror
-/* First thing to do is to get the page tables set up so that we can call the kernel
- * in the correct place.  This is relocatable code...
+/* First thing to do is to get the page tables set up so that we can call
+ * the kernel in the correct place.  This is relocatable code...
  * - Read processor ID register (CP#15, CR0).
  */
                mrc     p15, 0, r9, c0, c0                      @ get Processor ID
@@ -74,7 +99,7 @@ __entry:      teq     r0, #0                                  @ check for illegal entry...
 
                adr     r4, .LCMachTypes
                add     r4, r4, r1, lsl #4
-               ldmia   r4, {r4, r5, r6}
+               ldmia   r4, {r4, r5, r6, r7}
 /*
  * r4 = page dir in physical ram
  * r5 = physical address of start of RAM
@@ -99,26 +124,28 @@ __entry:   teq     r0, #0                                  @ check for illegal entry...
                add     r3, r3, #1 << 20
                str     r3, [r0], #4
                add     r3, r3, #1 << 20
-#ifdef DEBUG
+#ifdef CONFIG_DEBUG_LL
 /* Map in IO space
  * This allows debug messages to be output via a serial
  * before/while paging_init.
  */
-               add     r0, r4, #0x3800
+               add     r0, r4, r7
                orr     r3, r6, r8
                add     r2, r0, #0x0800
 1:             str     r3, [r0], #4
                add     r3, r3, #1 << 20
                teq     r0, r2
                bne     1b
-#ifdef CONFIG_ARCH_VNC
-               add     r0, r4, #0x3f00
-               add     r0, r0, #0x00f8
+#ifdef CONFIG_ARCH_NETWINDER
+               teq     r1, #5
+               bne     1f
+               add     r0, r4, #0x3fc0
                mov     r3, #0x7c000000
                orr     r3, r3, r8
                str     r3, [r0], #4
                add     r3, r3, #1 << 20
                str     r3, [r0], #4
+1:
 #endif
 #endif
 #ifdef CONFIG_ARCH_RPC
@@ -168,49 +195,55 @@ __entry:  teq     r0, #0                                  @ check for illegal entry...
 .LCMachTypes:  .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000        @ Address of page tables (physical)
                .long   0                                       @ Address of RAM
                .long   0xe0000000                              @ I/O address
-               .long   0
+               .long   0x3800
 
                @ Acorn RiscPC
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000
                .long   0x10000000
                .long   0x03000000
-               .long   0
+               .long   0x3800
 
                @ EBSIT ???
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000
                .long   0
                .long   0xe0000000
-               .long   0
+               .long   0x3800
 
                @ NexusPCI
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x40000000
                .long   0x40000000
                .long   0x10000000
-               .long   0
+               .long   0x3800
 
                @ DEC EBSA285
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
                .long   0                                       @ Address of RAM
                .long   0x24000000                              @ I/O base address (0x42000000 -> 0xFE000000)
-               .long   0
+               .long   0x3800
 
                @ Corel VNC
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
                .long   0                                       @ Address of RAM
                .long   0x24000000                              @ I/O base address (0x42000000 -> 0xfe000000)
-               .long   0
+               .long   0x3800
 
                @ CATS
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
                .long   0                                       @ Address of RAM
                .long   0x24000000                              @ I/O base address (0x42000000 -> 0xfe000000)
-               .long   0
+               .long   0x3800
 
                @ tbox
                .long   SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x80000000
                .long   0x80000000                              @ Address of RAM
                .long   0x00400000                              @ Uart
-               .long   0
+               .long   0x3800
+
+               @ DEC EBSA285 as co-processor
+               .long   0x4000                                  @ Address of page tables (physical)
+               .long   0                                       @ Address of RAM
+               .long   DC21285_ARMCSR_BASE                     @ Physical I/O base address
+               .long   0x7cf00000 >> 18                        @ Virtual I/O base address
 
 .LCProcTypes:  @ ARM6 / 610
                .long   0x41560600
@@ -250,7 +283,11 @@ __entry:   teq     r0, #0                                  @ check for illegal entry...
                mcr     p15, 0, r4, c2, c0                      @ load page table pointer
                mov     r0, #0x1f                               @ Domains 0, 1 = client
                mcr     p15, 0, r0, c3, c0                      @ load domain access register
+#ifdef CONFIG_ALIGNMENT_TRAP
+               mov     r0, #0x3f                               @ ....S..DPWCAM
+#else
                mov     r0, #0x3d                               @ ....S..DPWC.M
+#endif
                orr     r0, r0, #0x100
                mov     pc, lr
 
@@ -261,7 +298,11 @@ __entry:   teq     r0, #0                                  @ check for illegal entry...
                mcr     p15, 0, r4, c2, c0                      @ load page table pointer
                mov     r0, #0x1f                               @ Domains 0, 1 = client
                mcr     p15, 0, r0, c3, c0                      @ load domain access register
+#ifdef CONFIG_ALIGNMENT_TRAP
+               mov     r0, #0x7f                               @ ....S.LDPWCAM
+#else
                mov     r0, #0x7d                               @ ....S.LDPWC.M
+#endif
                orr     r0, r0, #0x100
                mov     pc, lr
 
@@ -276,32 +317,38 @@ __entry:  teq     r0, #0                                  @ check for illegal entry...
                mrc     p15, 0, r0, c1, c0                      @ get control register v4
                bic     r0, r0, #0x0e00
                bic     r0, r0, #0x0002
+#ifdef CONFIG_ALIGNMENT_TRAP
+               orr     r0, r0, #0x003f                         @ I...S..DPWCAM
+#else
                orr     r0, r0, #0x003d                         @ I...S..DPWC.M
+#endif
                orr     r0, r0, #0x1100                         @ v4 supports separate I cache
                mov     pc, lr
 
-               .section ".text.init",#alloc,#execinstr
-
 .Lsa_fastclock:        mcr     p15, 0, r4, c15, c1, 2                  @ Enable clock switching
                mov     pc, lr
 
 .LC0:          .long   SYMBOL_NAME(__entry)
-               .long   SYMBOL_NAME(machine_type)
+               .long   SYMBOL_NAME(__machine_arch_type)
                .long   SYMBOL_NAME(__bss_start)
                .long   SYMBOL_NAME(processor_id)
                .long   SYMBOL_NAME(_end)
+               .long   SYMBOL_NAME(cr_alignment)
                .long   SYMBOL_NAME(init_task_union)+8192
                .align
 
 .Lalready_done_mmap:
                adr     r4, .LC0
-               ldmia   r4, {r3, r4, r5, r6, r8, sp}            @ Setup stack
+               ldmia   r4, {r3, r4, r5, r6, r7, r8, sp}        @ Setup stack
                add     r10, r10, r3                            @ Add base back in
                mov     fp, #0
-1:             cmp     r5, r8                                  @ Clear BSS
+1:             cmp     r5, r7                                  @ Clear BSS
                strcc   fp, [r5],#4
                bcc     1b
 
+               bic     r2, r0, #2                              @ Clear 'A' bit
+               stmia   r8, {r0, r2}                            @ Save control register values
+
                str     r1, [r4]                                @ Save machine type
                str     r9, [r6]                                @ Save processor ID
                mov     lr, pc
@@ -310,10 +357,12 @@ __entry:  teq     r0, #0                                  @ check for illegal entry...
                b       SYMBOL_NAME(start_kernel)
 
                .text
-#ifdef DEBUG
+
+#ifdef CONFIG_DEBUG_LL
 /*
  * Some debugging routines (useful if you've got MM problems and
- * printk isn't working).  For DEBUGGING ONLY!!!
+ * printk isn't working).  For DEBUGGING ONLY!!!  Do not leave
+ * references to these in a production kernel!
  */
 #if defined(CONFIG_ARCH_RPC)
                .macro  addruart,rx
@@ -362,64 +411,71 @@ __entry:  teq     r0, #0                                  @ check for illegal entry...
                beq     1001b
                .endm
 
-#elif defined(CONFIG_ARCH_EBSA285)
+#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
+#ifndef CONFIG_DEBUG_DC21285_PORT
+       /* For NetWinder debugging */
                .macro  addruart,rx
-               mov     \rx, #0xfe000000
+               mov     \rx, #0xff000000
+               orr     \rx, \rx, #0x000003f8
                .endm
 
                .macro  senduart,rd,rx
-               str     \rd, [\rx, #0x160]      @ UARTDR
+               strb    \rd, [\rx]
                .endm
 
                .macro  busyuart,rd,rx
-1001:          ldr     \rd, [\rx, #0x178]      @ UARTFLG
-               tst     \rd, #1 << 3
-               bne     1001b
+1002:          ldrb    \rd, [\rx, #0x5]
+               and     \rd, \rd, #0x60
+               teq     \rd, #0x60
+               bne     1002b
                .endm
 
                .macro  waituart,rd,rx
+1001:          ldrb    \rd, [\rx, #0x6]
+               tst     \rd, #0x10
+               beq     1001b
                .endm
+#else
+       /* For EBSA285 debugging */
+               .equ    dc21285_high, ARMCSR_BASE & 0xff000000
+               .equ    dc21285_low,  ARMCSR_BASE & 0x00ffffff
 
-#elif defined(CONFIG_ARCH_NEXUSPCI)
                .macro  addruart,rx
-               ldr     \rx, =0xfff00000
+               mov     \rx, #dc21285_high
+               .if     dc21285_low
+               orr     \rx, \rx, #dc21285_low
+               .endif
                .endm
 
                .macro  senduart,rd,rx
-               str     \rd, [\rx, #0xc]
+               str     \rd, [\rx, #0x160]      @ UARTDR
                .endm
 
                .macro  busyuart,rd,rx
-1001:          ldr     \rd, [\rx, #0x4]
-               tst     \rd, #1 << 0
+1001:          ldr     \rd, [\rx, #0x178]      @ UARTFLG
+               tst     \rd, #1 << 3
                bne     1001b
                .endm
 
                .macro  waituart,rd,rx
                .endm
-
-#elif defined(CONFIG_ARCH_VNC)
+#endif
+#elif defined(CONFIG_ARCH_NEXUSPCI)
                .macro  addruart,rx
-               mov     \rx, #0xff000000
-               orr     \rx, \rx, #0x00e00000
-               orr     \rx, \rx, #0x000003f8
+               ldr     \rx, =0xfff00000
                .endm
 
                .macro  senduart,rd,rx
-               strb    \rd, [\rx]
+               str     \rd, [\rx, #0xc]
                .endm
 
                .macro  busyuart,rd,rx
-1002:          ldrb    \rd, [\rx, #0x5]
-               and     \rd, \rd, #0x60
-               teq     \rd, #0x60
-               bne     1002b
+1001:          ldr     \rd, [\rx, #0x4]
+               tst     \rd, #1 << 0
+               bne     1001b
                .endm
 
                .macro  waituart,rd,rx
-1001:          ldrb    \rd, [\rx, #0x6]
-               tst     \rd, #0x10
-               beq     1001b
                .endm
 #else
 #error Unknown architecture
@@ -476,8 +532,6 @@ ENTRY(printch)
                mov     r0, #0
                b       1b
 
-               .ltorg
-
                .bss
 hexbuf:                .space 16
 
diff --git a/arch/arm/kernel/hw-ebsa285.c b/arch/arm/kernel/hw-ebsa285.c
deleted file mode 100644 (file)
index e338569..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * arch/arm/kernel/hw-ebsa286.c
- *
- * EBSA285 hardware specific functions
- *
- * Copyright (C) 1998 Russell King, Phil Blundel
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ptrace.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/system.h>
-
-extern int setup_arm_irq(int, struct irqaction *);
-
-extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set);
-extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr);
-extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq);
-
-static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
-static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
-
-__initfunc(static int ebsa_irqval(struct pci_dev *dev))
-{
-       unsigned char pin;
-       
-       pcibios_read_config_byte(dev->bus->number,
-                                dev->devfn,
-                                PCI_INTERRUPT_PIN,
-                                &pin);
-       
-       return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
-}
-
-__initfunc(static int cats_irqval(struct pci_dev *dev))
-{
-       if (dev->irq >= 128)
-               return 32 + (dev->irq & 0x1f);
-
-       switch (dev->irq) {
-       case 1:
-       case 2:
-       case 3:
-       case 4:
-               return irqmap_cats[dev->irq - 1];
-       case 0:
-               return 0;
-       }
-
-       printk("PCI: device %02x:%02x has unknown irq line %x\n",
-              dev->bus->number, dev->devfn, dev->irq);
-       return 0;
-}
-
-__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev))
-{
-       char cmd;
-
-       /* sort out the irq mapping for this device */
-       switch (machine_type) {
-       case MACH_TYPE_EBSA285:
-               dev->irq = ebsa_irqval(dev);
-               break;
-       case MACH_TYPE_CATS:
-               dev->irq = cats_irqval(dev);
-               break;
-       }
-
-       /* Turn on bus mastering - boot loader doesn't
-        * - perhaps it should! - dag
-        */
-       pci_read_config_byte(dev, PCI_COMMAND, &cmd);
-       pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
-}
-
-static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
-{
-       const char *err = "unknown";
-       unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff;
-       unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07;
-       static unsigned long next_warn[7];
-       int idx = 6;
-
-       switch(irq) {
-       case IRQ_PCIPARITY:
-               *(unsigned long *)0xfe000004 = cmd | 1 << 31;
-               idx = 0;
-               err = "parity";
-               break;
-
-       case IRQ_PCITARGETABORT:
-               *(unsigned long *)0xfe000004 = cmd | 1 << 28;
-               idx = 1;
-               err = "target abort";
-               break;
-
-       case IRQ_PCIMASTERABORT:
-               *(unsigned long *)0xfe000004 = cmd | 1 << 29;
-               idx = 2;
-               err = "master abort";
-               break;
-
-       case IRQ_PCIDATAPARITY:
-               *(unsigned long *)0xfe000004 = cmd | 1 << 24;
-               idx = 3;
-               err = "data parity";
-               break;
-
-       case IRQ_DISCARDTIMER:
-               *(unsigned long *)0xfe00013c = ctrl | 1 << 8;
-               idx = 4;
-               err = "discard timer";
-               break;
-
-       case IRQ_SERR:
-               *(unsigned long *)0xfe00013c = ctrl | 1 << 3;
-               idx = 5;
-               err = "system";
-               break;
-       }
-       if (time_after_eq(jiffies, next_warn[idx])) {
-               next_warn[idx] = jiffies + 3 * HZ / 100;
-               printk(KERN_ERR "PCI %s error detected\n", err);
-       }
-}
-
-static struct irqaction irq_pci_error = {
-       irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL
-};
-
-__initfunc(void pcibios_init_ebsa285(void))
-{
-       setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error);
-       setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error);
-       setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error);
-       setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error);
-       setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error);
-       setup_arm_irq(IRQ_SERR, &irq_pci_error);
-
-       /*
-        * Map our SDRAM at a known address in PCI space, just in case
-        * the firmware had other ideas.  Using a nonzero base is slightly
-        * bizarre but apparently necessary to avoid problems with some
-        * video cards.
-        *
-        * We should really only do this if the central function is enabled.
-        */
-       *(unsigned long *)0xfe000010 = 0;
-       *(unsigned long *)0xfe000018 = 0xe0000000;
-       *(unsigned long *)0xfe0000f8 = 0;
-       *(unsigned long *)0xfe0000fc = 0;
-       *(unsigned long *)0xfe000100 = 0x01fc0000;
-       *(unsigned long *)0xfe000104 = 0;
-       *(unsigned long *)0xfe000108 = 0x80000000;
-       *(unsigned long *)0xfe000004 = 0x17;
-}
diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c
new file mode 100644 (file)
index 0000000..857f120
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * arch/arm/kernel/hw-footbridge.c
+ *
+ * Footbridge-dependent machine fixup
+ *
+ * Copyright (C) 1998, 1999 Russell King, Phil Blundell
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/dec21285.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#define IRDA_IO_BASE           0x180
+#define ETHER10_IO_BASE                0x301
+#define GP1_IO_BASE            0x338
+#define GP2_IO_BASE            0x33a
+#define DEC21143_IO_BASE       0x401
+#define DEC21143_MEM_BASE      0x00800000
+#define CYBER2000_MEM_BASE     0x01000000
+
+int    have_isa_bridge;
+
+extern int setup_arm_irq(int, struct irqaction *);
+extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set);
+extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr);
+extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+
+#ifdef CONFIG_PCI
+
+static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
+
+__initfunc(static int ebsa_irqval(struct pci_dev *dev))
+{
+       unsigned char pin;
+       
+       pcibios_read_config_byte(dev->bus->number,
+                                dev->devfn,
+                                PCI_INTERRUPT_PIN,
+                                &pin);
+       
+       return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
+}
+
+#ifdef CONFIG_CATS
+static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
+
+__initfunc(static int cats_irqval(struct pci_dev *dev))
+{
+       if (dev->irq >= 128)
+               return 16 + (dev->irq & 0x1f);
+
+       switch (dev->irq) {
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               return irqmap_cats[dev->irq - 1];
+       case 0:
+               return 0;
+       }
+
+       printk("PCI: device %02x:%02x has unknown irq line %x\n",
+              dev->bus->number, dev->devfn, dev->irq);
+       return 0;
+}
+#endif
+
+__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev))
+{
+       /* Latency timer of 32 */
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
+
+       /* 32-byte cache line size */
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+
+       /* Set SysErr enable, Parity enable */
+       pci_set_cmd(dev, 0, PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+
+       /* If this device is an ISA bridge, set the
+        * have_isa_bridge flag.  We will then go looking
+        * for things like keyboard, etc
+        */
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA ||
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_EISA)
+               have_isa_bridge = !0;
+
+       /* sort out the irq mapping for this device */
+       switch (machine_arch_type) {
+       case MACH_TYPE_EBSA285:
+               dev->irq = ebsa_irqval(dev);
+               /* Turn on bus mastering - boot loader doesn't
+                * - perhaps it should! - dag
+                */
+               pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
+               break;
+
+#ifdef CONFIG_CATS
+       case MACH_TYPE_CATS:
+               dev->irq = cats_irqval(dev);
+               /* Turn on bus mastering - boot loader doesn't
+                * - perhaps it should! - dag
+                */
+               pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
+               break;
+#endif
+#ifdef CONFIG_ARCH_NETWINDER
+       case MACH_TYPE_NETWINDER:
+               /* disable ROM */
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+
+#define DEV(v,d) ((v)<<16|(d))
+               switch (DEV(dev->vendor, dev->device)) {
+               /* Ether 100 */
+               case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
+                       pci_set_base_addr(dev, 0, DEC21143_IO_BASE);
+                       pci_set_base_addr(dev, 1, DEC21143_MEM_BASE);
+                       pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+                       /* Put the chip to sleep in case the driver isn't loaded */
+                       pci_write_config_dword(dev, 0x40, 0x80000000);
+                       dev->irq = IRQ_NETWINDER_ETHER100;
+                       break;
+
+               /* Ether 10 */
+               case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a):
+                       pci_set_base_addr(dev, 0, ETHER10_IO_BASE);
+                       pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
+                       dev->irq = IRQ_NETWINDER_ETHER10;
+                       break;
+
+               /* ISA bridge */
+               case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553):
+                       pci_set_base_addr(dev, 0, 0);
+                       pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
+                       /*
+                        * Enable all memory requests from ISA to be channeled to PCI
+                        */
+                       pci_write_config_byte(dev, 0x48, 255);
+                       /*
+                        * Disable ping-pong (as per errata)
+                        */
+                       pci_write_config_byte(dev, 0x42, 0);
+                       /*
+                        * Enable PCI packet retry
+                        */
+                       pci_write_config_byte(dev, 0x40, 0x22);
+                       /*
+                        * Do not use PCI CPU park enable, park on
+                        * last master, disable GAT bit
+                        */
+                       pci_write_config_byte(dev, 0x83, 0x02);
+                       /*
+                        * Default rotating priorities
+                        */
+                       pci_write_config_byte(dev, 0x80, 0xe0);
+                       /*
+                        * Rotate bank 4
+                        */
+                       pci_write_config_byte(dev, 0x81, 0x01);
+                       break;
+
+               /* IDE */
+               case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105):
+                       pci_set_base_addr(dev, 0, 0x1f1);
+                       pci_set_base_addr(dev, 1, 0x3f5);
+                       pci_set_base_addr(dev, 2, 0x171);
+                       pci_set_base_addr(dev, 3, 0x375);
+                       pci_set_base_addr(dev, 4, 0xe801);
+                       pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+                       dev->irq = IRQ_ISA_HARDDISK1;
+                       break;
+
+               /* VGA */
+               case DEV(PCI_VENDOR_ID_INTERG,0x2000):
+                       pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE);
+                       pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+                       dev->irq = IRQ_NETWINDER_VGA;
+                       break;
+               }
+#endif
+       }
+}
+
+static inline void
+report_pci_dev_error(void)
+{
+       struct pci_dev *dev;
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               unsigned short status;
+
+               pci_read_config_word(dev, PCI_STATUS, &status);
+               if (status & 0xf900) {
+                       printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n",
+                               dev->vendor, dev->device, status);
+
+                       pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
+               }
+       }
+}
+#else
+#define report_pci_dev_error()
+#endif
+
+/*
+ * Warn on PCI errors.  Please report any occurances!
+ */
+static void
+irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
+{
+       static unsigned long next_warn;
+       unsigned long cmd       = *CSR_PCICMD & 0x0000ffff;
+       unsigned long ctrl      = (*CSR_SA110_CNTL) & 0xffffde07;
+       unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
+       int warn = time_after_eq(jiffies, next_warn);
+
+       ctrl |= SA110_CNTL_DISCARDTIMER;
+
+       if (warn) {
+               next_warn = jiffies + 3 * HZ / 100;
+               printk(KERN_DEBUG "PCI: ");
+       }
+
+       if (irqstatus & (1 << 31)) {
+               if (warn)
+                       printk("parity error ");
+               cmd |= 1 << 31;
+       }
+
+       if (irqstatus & (1 << 30)) {
+               if (warn)
+                       printk("target abort ");
+               cmd |= 1 << 28;
+       }
+
+       if (irqstatus & (1 << 29)) {
+               if (warn)
+                       printk("master abort ");
+               cmd |= 1 << 29;
+       }
+
+       if (irqstatus & (1 << 28)) {
+               if (warn)
+                       printk("data parity error ");
+               cmd |= 1 << 24;
+       }
+
+       if (irqstatus & (1 << 27)) {
+               if (warn)
+                       printk("discard timer expired ");
+               ctrl &= ~SA110_CNTL_DISCARDTIMER;
+       }
+
+       if (irqstatus & (1 << 23)) {
+               if (warn)
+                       printk("system error ");
+               ctrl |= SA110_CNTL_RXSERR;
+       }
+
+       if (warn)
+               printk("pc=[<%08lX>]\n", instruction_pointer(regs));
+
+       report_pci_dev_error();
+
+       *CSR_PCICMD = cmd;
+       *CSR_SA110_CNTL = ctrl;
+}
+
+static struct irqaction irq_pci_error = {
+       irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL
+};
+
+__initfunc(void pcibios_init_ebsa285(void))
+{
+       setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error);
+}
+
+/*
+ * Netwinder stuff
+ */
+#ifdef CONFIG_ARCH_NETWINDER
+
+/*
+ * Winbond WB83977F accessibility stuff
+ */
+static inline void wb977_open(void)
+{
+       outb(0x87, 0x370);
+       outb(0x87, 0x370);
+}
+
+static inline void wb977_close(void)
+{
+       outb(0xaa, 0x370);
+}
+
+static inline void wb977_wb(int reg, int val)
+{
+       outb(reg, 0x370);
+       outb(val, 0x371);
+}
+
+static inline void wb977_ww(int reg, int val)
+{
+       outb(reg, 0x370);
+       outb(val >> 8, 0x371);
+       outb(reg + 1, 0x370);
+       outb(val, 0x371);
+}
+
+#define wb977_device_select(dev)       wb977_wb(0x07, dev)
+#define wb977_device_disable()         wb977_wb(0x30, 0x00)
+#define wb977_device_enable()          wb977_wb(0x30, 0x01)
+
+/*
+ * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE
+ */
+spinlock_t __netwinder_data gpio_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned int __netwinder_data current_gpio_op = 0;
+static unsigned int __netwinder_data current_gpio_io = 0;
+static unsigned int __netwinder_data current_cpld = 0;
+
+void __netwinder_text gpio_modify_op(int mask, int set)
+{
+       unsigned int new_gpio, changed;
+
+       new_gpio = (current_gpio_op & ~mask) | set;
+       changed = new_gpio ^ current_gpio_op;
+       current_gpio_op = new_gpio;
+
+       if (changed & 0xff)
+               outb(new_gpio, GP1_IO_BASE);
+       if (changed & 0xff00)
+               outb(new_gpio >> 8, GP2_IO_BASE);
+}
+
+static inline void __gpio_modify_io(int mask, int in)
+{
+       unsigned int new_gpio, changed;
+       int port;
+
+       new_gpio = (current_gpio_io & ~mask) | in;
+       changed = new_gpio ^ current_gpio_io;
+       current_gpio_io = new_gpio;
+
+       changed >>= 1;
+       new_gpio >>= 1;
+
+       wb977_device_select(7);
+
+       for (port = 0xe1; changed && port < 0xe8; changed >>= 1) {
+               wb977_wb(port, new_gpio & 1);
+
+               port += 1;
+               new_gpio >>= 1;
+       }
+
+       wb977_device_select(8);
+
+       for (port = 0xe8; changed && port < 0xec; changed >>= 1) {
+               wb977_wb(port, new_gpio & 1);
+
+               port += 1;
+               new_gpio >>= 1;
+       }
+}
+
+void __netwinder_text gpio_modify_io(int mask, int in)
+{
+       /* Open up the SuperIO chip */
+       wb977_open();
+
+       __gpio_modify_io(mask, in);
+
+       /* Close up the EFER gate */
+       wb977_close();
+}
+
+int __netwinder_text gpio_read(void)
+{
+       return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8;
+}
+
+/*
+ * Initialise the Winbond W83977F global registers
+ */
+static inline void wb977_init_global(void)
+{
+       /*
+        * Enable R/W config registers
+        */
+       wb977_wb(0x26, 0x40);
+
+       /*
+        * Power down FDC (not used)
+        */
+       wb977_wb(0x22, 0xfe);
+
+       /*
+        * GP12, GP11, CIRRX, IRRXH, GP10
+        */
+       wb977_wb(0x2a, 0xc1);
+
+       /*
+        * GP23, GP22, GP21, GP20, GP13
+        */
+       wb977_wb(0x2b, 0x6b);
+
+       /*
+        * GP17, GP16, GP15, GP14
+        */
+       wb977_wb(0x2c, 0x55);
+}
+
+/*
+ * Initialise the Winbond W83977F printer port
+ */
+static inline void wb977_init_printer(void)
+{
+       wb977_device_select(1);
+
+       /*
+        * mode 1 == EPP
+        */
+       wb977_wb(0xf0, 0x01);
+}
+
+/*
+ * Initialise the Winbond W83977F keyboard controller
+ */
+static inline void wb977_init_keyboard(void)
+{
+       wb977_device_select(5);
+
+       /*
+        * Keyboard controller address
+        */
+       wb977_ww(0x60, 0x0060);
+       wb977_ww(0x62, 0x0064);
+
+       /*
+        * Keyboard IRQ 1, active high, edge trigger
+        */
+       wb977_wb(0x70, 1);
+       wb977_wb(0x71, 0x02);
+
+       /*
+        * Mouse IRQ 5, active high, edge trigger
+        */
+       wb977_wb(0x72, 5);
+       wb977_wb(0x73, 0x02);
+
+       /*
+        * KBC 8MHz
+        */
+       wb977_wb(0xf0, 0x40);
+
+       /*
+        * Enable device
+        */
+       wb977_device_enable();
+}
+
+/*
+ * Initialise the Winbond W83977F Infra-Red device
+ */
+static inline void wb977_init_irda(void)
+{
+       wb977_device_select(6);
+
+       /*
+        * IR base address
+        */
+       wb977_ww(0x60, IRDA_IO_BASE);
+
+       /*
+        * IRDA IRQ 6, active high, edge trigger
+        */
+       wb977_wb(0x70, 6);
+       wb977_wb(0x71, 0x02);
+
+       /*
+        * RX DMA - ISA DMA 0
+        */
+       wb977_wb(0x74, 0x00);
+
+       /*
+        * TX DMA - Disable Tx DMA
+        */
+       wb977_wb(0x75, 0x04);
+
+       /*
+        * Append CRC, Enable bank selection
+        */
+       wb977_wb(0xf0, 0x03);
+
+       /*
+        * Enable device
+        */
+       wb977_device_enable();
+}
+
+/*
+ * Initialise Winbond W83977F general purpose IO
+ */
+static inline void wb977_init_gpio(void)
+{
+       unsigned long flags;
+
+       /*
+        * Set up initial I/O definitions
+        */
+       current_gpio_io = -1;
+       __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER);
+
+       wb977_device_select(7);
+
+       /*
+        * Group1 base address
+        */
+       wb977_ww(0x60, GP1_IO_BASE);
+       wb977_ww(0x62, 0);
+       wb977_ww(0x64, 0);
+
+       /*
+        * GP10 (Orage button) IRQ 10, active high, edge trigger
+        */
+       wb977_wb(0x70, 10);
+       wb977_wb(0x71, 0x02);
+
+       /*
+        * GP10: Debounce filter enabled, IRQ, input
+        */
+       wb977_wb(0xe0, 0x19);
+
+       /*
+        * Enable Group1
+        */
+       wb977_device_enable();
+
+       wb977_device_select(8);
+
+       /*
+        * Group2 base address
+        */
+       wb977_ww(0x60, GP2_IO_BASE);
+
+       /*
+        * Clear watchdog timer regs
+        *  - timer disable
+        */
+       wb977_wb(0xf2, 0x00);
+
+       /*
+        *  - disable LED, no mouse nor keyboard IRQ
+        */
+       wb977_wb(0xf3, 0x00);
+
+       /*
+        *  - timer counting, disable power LED, disable timeouot
+        */
+       wb977_wb(0xf4, 0x00);
+
+       /*
+        * Enable group2
+        */
+       wb977_device_enable();
+
+       /*
+        * Set Group1/Group2 outputs
+        */
+       spin_lock_irqsave(&gpio_lock, flags);
+       gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
+       spin_unlock_irqrestore(&gpio_loc, flags);
+}
+
+/*
+ * Initialise the Winbond W83977F chip.
+ */
+__initfunc(static void wb977_init(void))
+{
+       request_region(0x370, 2, "W83977AF configuration");
+
+       /*
+        * Open up the SuperIO chip
+        */
+       wb977_open();
+
+       /*
+        * Initialise the global registers
+        */
+       wb977_init_global();
+
+       /*
+        * Initialise the various devices in
+        * the multi-IO chip.
+        */
+       wb977_init_printer();
+       wb977_init_keyboard();
+       wb977_init_irda();
+       wb977_init_gpio();
+
+       /*
+        * Close up the EFER gate
+        */
+       wb977_close();
+}
+
+void __netwinder_text cpld_modify(int mask, int set)
+{
+       int msk;
+
+       current_cpld = (current_cpld & ~mask) | set;
+
+       gpio_modify_io(GPIO_DATA, 0);
+       gpio_modify_op(GPIO_IOLOAD, 0);
+
+       for (msk = 8; msk; msk >>= 1) {
+               int bit = current_cpld & msk;
+
+               gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);
+               gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);
+       }
+
+       gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);
+       gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);
+       gpio_modify_op(GPIO_IOLOAD, 0);
+}
+
+__initfunc(static void cpld_init(void))
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+       cpld_modify(-1, CPLD_UNMUTE | 4);
+       spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static unsigned char rwa_unlock[] __initdata =
+{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b,
+  0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74,
+  0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
+
+#ifndef DEBUG
+#define dprintk if (0) printk
+#else
+#define dprintk printk
+#endif
+
+#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0)
+
+static inline void rwa010_unlock(void)
+{
+       int i;
+
+       WRITE_RWA(2, 2);
+       mdelay(10);
+
+       for (i = 0; i < sizeof(rwa_unlock); i++)
+               outb(rwa_unlock[i], 0x279);
+}
+
+static inline void rwa010_read_ident(void)
+{
+       unsigned char si[9];
+       int i, j;
+
+       WRITE_RWA(3, 0);
+       WRITE_RWA(0, 128);
+
+       outb(1, 0x279);
+
+       mdelay(10);
+
+       dprintk("Identifier: ");
+       for (i = 0; i < 9; i++) {
+               si[i] = 0;
+               for (j = 0; j < 8; j++) {
+                       int bit;
+                       mdelay(1);
+                       inb(0x203);
+                       mdelay(1);
+                       bit = inb(0x203);
+                       dprintk("%02X ", bit);
+                       si[i] |= bit << j;
+               }
+               mdelay(10);
+               dprintk("%02X ", si[i]);
+       }
+       dprintk("\n");
+}
+
+static inline void rwa010_global_init(void)
+{
+       WRITE_RWA(6, 2);        // Assign a card no = 2
+
+       dprintk("Card no = %d\n", inb(0x203));
+
+       WRITE_RWA(7, 3);
+       WRITE_RWA(0x30, 0);
+
+       WRITE_RWA(7, 4);
+       WRITE_RWA(0x30, 0);
+
+       WRITE_RWA(7, 2);
+       WRITE_RWA(0x30, 0);
+}
+
+static inline void rwa010_game_port_init(void)
+{
+       int i;
+
+       WRITE_RWA(7, 5);
+
+       dprintk("Slider base: ");
+       WRITE_RWA(0x61, 1);
+       i = inb(0x203);
+
+       WRITE_RWA(0x60, 2);
+       dprintk("%02X%02X (201)\n", inb(0x203), i);
+
+       WRITE_RWA(0x30, 1);
+}
+
+static inline void rwa010_waveartist_init(int base, int irq, int dma)
+{
+       int i;
+
+       WRITE_RWA(7, 0);
+
+       dprintk("WaveArtist base: ");
+       WRITE_RWA(0x61, base);
+       i = inb(0x203);
+
+       WRITE_RWA(0x60, base >> 8);
+       dprintk("%02X%02X (%X),", inb(0x203), i, base);
+
+       WRITE_RWA(0x70, irq);
+       dprintk(" irq: %d (%d),", inb(0x203), irq);
+
+       WRITE_RWA(0x74, dma);
+       dprintk(" dma: %d (%d)\n", inb(0x203), dma);
+
+       WRITE_RWA(0x30, 1);
+}
+
+static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma)
+{
+       int i;
+
+       WRITE_RWA(7, 1);
+
+       dprintk("SoundBlaster base: ");
+       WRITE_RWA(0x61, sb_base);
+       i = inb(0x203);
+
+       WRITE_RWA(0x60, sb_base >> 8);
+       dprintk("%02X%02X (%X),", inb(0x203), i, sb_base);
+
+       dprintk(" irq: ");
+       WRITE_RWA(0x70, irq);
+       dprintk("%d (%d),", inb(0x203), irq);
+
+       dprintk(" 8-bit DMA: ");
+       WRITE_RWA(0x74, dma);
+       dprintk("%d (%d)\n", inb(0x203), dma);
+
+       dprintk("AdLib base: ");
+       WRITE_RWA(0x63, al_base);
+       i = inb(0x203);
+
+       WRITE_RWA(0x62, al_base >> 8);
+       dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base);
+
+       WRITE_RWA(0x30, 1);
+}
+
+static void rwa010_soundblaster_reset(void)
+{
+       int i;
+
+       outb(1, 0x226);
+       udelay(3);
+       outb(0, 0x226);
+
+       for (i = 0; i < 5; i++) {
+               if (inb(0x22e) & 0x80)
+                       break;
+               mdelay(1);
+       }
+       if (i == 5)
+               printk("SoundBlaster: DSP reset failed\n");
+
+       dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a));
+
+       for (i = 0; i < 5; i++) {
+               if ((inb(0x22c) & 0x80) == 0)
+                       break;
+               mdelay(1);
+       }
+
+       if (i == 5)
+               printk("SoundBlaster: DSP not ready\n");
+       else {
+               outb(0xe1, 0x22c);
+
+               dprintk("SoundBlaster DSP id: ");
+               i = inb(0x22a);
+               udelay(1);
+               i |= inb(0x22a) << 8;
+               dprintk("%04X\n", i);
+
+               for (i = 0; i < 5; i++) {
+                       if ((inb(0x22c) & 0x80) == 0)
+                               break;
+                       mdelay(1);
+               }
+
+               if (i == 5)
+                       printk("SoundBlaster: could not turn speaker off\n");
+
+               outb(0xd3, 0x22c);
+       }
+
+       /* turn on OPL3 */
+       outb(5, 0x38a);
+       outb(1, 0x38b);
+}
+
+__initfunc(static void rwa010_init(void))
+{
+       rwa010_unlock();
+       rwa010_read_ident();
+       rwa010_global_init();
+       rwa010_game_port_init();
+       rwa010_waveartist_init(0x250, 3, 7);
+       rwa010_soundblaster_init(0x220, 0x388, 3, 1);
+       rwa010_soundblaster_reset();
+}
+
+EXPORT_SYMBOL(gpio_lock);
+EXPORT_SYMBOL(gpio_modify_op);
+EXPORT_SYMBOL(gpio_modify_io);
+EXPORT_SYMBOL(cpld_modify);
+
+#endif
+
+#ifdef CONFIG_LEDS
+#define DEFAULT_LEDS   0
+#else
+#define DEFAULT_LEDS   GPIO_GREEN_LED
+#endif
+
+__initfunc(void hw_init(void))
+{
+#ifdef CONFIG_ARCH_NETWINDER
+       /*
+        * this ought to have a better home...
+        * Since this calls the above routines, which are
+        * compiled only if CONFIG_ARCH_NETWINDER is set,
+        * these should only be parsed by the compiler
+        * in the same circumstance.
+        */
+       if (machine_is_netwinder()) {
+               unsigned long flags;
+
+               wb977_init();
+               cpld_init();
+               rwa010_init();
+
+               spin_lock_irqsave(&gpio_lock, flags);
+               gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
+               spin_unlock_irqrestore(&gpio_lock, flags);
+       }
+#endif
+
+       leds_event(led_start);
+}
index 6eb0122e892e1d7dbabcd1819d29b28aaf5d2c8c..c9a672a321c44fe598f708ede9745f5bfd9649f7 100644 (file)
@@ -7,20 +7,24 @@
  */
 
 #include <linux/delay.h>
+#include <linux/errno.h>
 
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/ioc.h>
+
+#define FORCE_ONES     0xdc
 
 /*
  * if delay loop has been calibrated then us that,
  * else use IOC timer 1.
  */
-static void iic_delay (void)
+static void iic_delay(void)
 {
        extern unsigned long loops_per_sec;
        if (loops_per_sec != (1 << 12)) {
-               udelay(10);
+               udelay(100); /* was 10 */
                return;
        } else {
                unsigned long flags;
@@ -30,7 +34,7 @@ static void iic_delay (void)
                outb(255,  IOC_T1LTCHH);
                outb(0,    IOC_T1GO);
                outb(1<<6, IOC_IRQCLRA);                        /* clear T1 irq */
-               outb(4,    IOC_T1LTCHL);
+               outb(10,   IOC_T1LTCHL); /* was 4 */
                outb(0,    IOC_T1LTCHH);
                outb(0,    IOC_T1GO);
                while ((inb(IOC_IRQSTATA) & (1<<6)) == 0);
@@ -38,124 +42,207 @@ static void iic_delay (void)
        }
 }
 
-static inline void iic_start (void)
+#define IIC_INIT()             dat = (inb(IOC_CONTROL) | FORCE_ONES) & ~3
+#define IIC_SET_DAT            outb(dat|=1, IOC_CONTROL);
+#define IIC_CLR_DAT            outb(dat&=~1, IOC_CONTROL);
+#define IIC_SET_CLK            outb(dat|=2, IOC_CONTROL);
+#define IIC_CLR_CLK            outb(dat&=~2, IOC_CONTROL);
+#define IIC_DELAY              iic_delay();
+#define IIC_READ_DATA()                (inb(IOC_CONTROL) & 1)
+
+static inline void iic_set_lines(int clk, int dat)
 {
-       unsigned char out;
+       int old;
 
-       out = inb(IOC_CONTROL) | 0xc2;
+       old = inb(IOC_CONTROL) | FORCE_ONES;
 
-       outb(out, IOC_CONTROL);
-       iic_delay();
+       old &= ~3;
+
+       if (clk)
+               old |= 2;
+       if (dat)
+               old |= 1;
+
+       outb(old, IOC_CONTROL);
 
-       outb(out ^ 1, IOC_CONTROL);
        iic_delay();
 }
 
-static inline void iic_stop (void)
+static inline unsigned int iic_read_data(void)
 {
-       unsigned char out;
+       return inb(IOC_CONTROL) & 1;
+}
 
-       out = inb(IOC_CONTROL) | 0xc3;
+/*
+ * C: ==~~_
+ * D: =~~__
+ */
+static inline void iic_start(void)
+{
+       unsigned int dat;
 
-       iic_delay();
-       outb(out ^ 1, IOC_CONTROL);
+       IIC_INIT();
 
-       iic_delay();
-       outb(out, IOC_CONTROL);
+       IIC_SET_DAT
+       IIC_DELAY
+       IIC_SET_CLK
+       IIC_DELAY
+
+       IIC_CLR_DAT
+       IIC_DELAY
+       IIC_CLR_CLK
+       IIC_DELAY
 }
 
-static int iic_sendbyte (unsigned char b)
+/*
+ * C: __~~
+ * D: =__~
+ */
+static inline void iic_stop(void)
 {
-       unsigned char out, in;
-       int i;
+       unsigned int dat;
 
-       out = (inb(IOC_CONTROL) & 0xfc) | 0xc0;
+       IIC_INIT();
 
-       outb(out, IOC_CONTROL);
-       for (i = 7; i >= 0; i--) {
-               unsigned char c;
-               c = out | ((b & (1 << i)) ? 1 : 0);
+       IIC_CLR_DAT
+       IIC_DELAY
+       IIC_SET_CLK
+       IIC_DELAY
+       IIC_SET_DAT
+       IIC_DELAY
+}
 
-               outb(c, IOC_CONTROL);
-               iic_delay();
+/*
+ * C: __~_
+ * D: =___
+ */
+static inline void iic_acknowledge(void)
+{
+       unsigned int dat;
 
-               outb(c | 2, IOC_CONTROL);
-               iic_delay();
+       IIC_INIT();
 
-               outb(c, IOC_CONTROL);
-       }
-       outb(out | 1, IOC_CONTROL);
-       iic_delay();
+       IIC_CLR_DAT
+       IIC_DELAY
+       IIC_SET_CLK
+       IIC_DELAY
+       IIC_CLR_CLK
+       IIC_DELAY
+}
 
-       outb(out | 3, IOC_CONTROL);
-       iic_delay();
+/*
+ * C: __~_
+ * D: =~H~
+ */
+static inline int iic_is_acknowledged(void)
+{
+       unsigned int dat, ack_bit;
 
-       in = inb(IOC_CONTROL) & 1;
+       IIC_INIT();
 
-       outb(out | 1, IOC_CONTROL);
-       iic_delay();
+       IIC_SET_DAT
+       IIC_DELAY
+       IIC_SET_CLK
+       IIC_DELAY
 
-       outb(out, IOC_CONTROL);
-       iic_delay();
+       ack_bit = IIC_READ_DATA();
+
+       IIC_CLR_CLK
+       IIC_DELAY
+
+       return ack_bit == 0;
+}
+
+/*
+ * C: _~__~__~__~__~__~__~__~_
+ * D: =DDXDDXDDXDDXDDXDDXDDXDD
+ */
+static void iic_sendbyte(unsigned int b)
+{
+       unsigned int dat, i;
+
+       IIC_INIT();
+
+       for (i = 0; i < 8; i++) {
+               if (b & 128)
+                       IIC_SET_DAT
+               else
+                       IIC_CLR_DAT
+               IIC_DELAY
+
+               IIC_SET_CLK
+               IIC_DELAY
+               IIC_CLR_CLK
+               IIC_DELAY
 
-       if(in) {
-               printk("No acknowledge from RTC\n");
-               return 1;
-       } else
-               return 0;
+               b <<= 1;
+       }
 }
 
-static unsigned char iic_recvbyte (void)
+/*
+ * C: __~_~_~_~_~_~_~_~_
+ * D: =~HHHHHHHHHHHHHHHH
+ */
+static unsigned char iic_recvbyte(void)
 {
-       unsigned char out, in;
-       int i;
+       unsigned int dat, i, in;
 
-       out = (inb(IOC_CONTROL) & 0xfc) | 0xc0;
+       IIC_INIT();
+
+       IIC_SET_DAT
+       IIC_DELAY
 
-       outb(out, IOC_CONTROL);
        in = 0;
-       for (i = 7; i >= 0; i--) {
-               outb(out | 1, IOC_CONTROL);
-               iic_delay();
-               outb(out | 3, IOC_CONTROL);
-               iic_delay();
-               in = (in << 1) | (inb(IOC_CONTROL) & 1);
-               outb(out | 1, IOC_CONTROL);
-               iic_delay();
+       for (i = 0; i < 8; i++) {
+               IIC_SET_CLK
+               IIC_DELAY
+
+               in = (in << 1) | IIC_READ_DATA();
+
+               IIC_CLR_CLK
+               IIC_DELAY
        }
-       outb(out, IOC_CONTROL);
-       iic_delay();
-       outb(out | 2, IOC_CONTROL);
-       iic_delay();
 
        return in;
 }
 
-void iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len)
+int iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len)
 {
-       iic_start();
+       int i, err = -EIO;
 
-       if (iic_sendbyte(addr & 0xfe))
+       iic_start();
+       iic_sendbyte(addr & 0xfe);
+       if (!iic_is_acknowledged())
                goto error;
 
-       if (iic_sendbyte(loc))
+       iic_sendbyte(loc);
+       if (!iic_is_acknowledged())
                goto error;
 
        if (addr & 1) {
-               int i;
-
-               for (i = 0; i < len; i++)
-                       if (iic_sendbyte (buf[i]))
-                               break;
-       } else {
-               int i;
-
                iic_stop();
                iic_start();
                iic_sendbyte(addr|1);
-               for (i = 0; i < len; i++)
-                       buf[i] = iic_recvbyte ();
+               if (!iic_is_acknowledged())
+                       goto error;
+
+               for (i = 0; i < len - 1; i++) {
+                       buf[i] = iic_recvbyte();
+                       iic_acknowledge();
+               }
+               buf[i] = iic_recvbyte();
+       } else {
+               for (i = 0; i < len; i++) {
+                       iic_sendbyte(buf[i]);
+
+                       if (!iic_is_acknowledged())
+                               goto error;
+               }
        }
+
+       err = 0;
 error:
        iic_stop();
+
+       return err;
 }
index 99577f1b7d73bf3e6e9cab3b9d96e3cf9b755a09..5d09ea54009c6b3ed4d44f25971a84c4269f5417 100644 (file)
@@ -6,9 +6,10 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
  * Initial task structure.
@@ -20,4 +21,5 @@ struct mm_struct init_mm = INIT_MM;
  *
  * The things we do for performance..
  */
-union task_union init_task_union __attribute__((__section__(".init.task"))) = { INIT_TASK };
+union task_union init_task_union __attribute__((__section__(".init.task"))) =
+               { INIT_TASK(init_task_union.task) };
diff --git a/arch/arm/kernel/ioport.c b/arch/arm/kernel/ioport.c
deleted file mode 100644 (file)
index d375dcb..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * linux/arch/arm/kernel/ioport.c
- *
- * Io-port support is not used for ARM
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-
-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-/*asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
-{
-}*/
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
-       return -ENOSYS;
-}
-
-asmlinkage int sys_iopl(long ebx,long ecx,long edx,
-            long esi, long edi, long ebp, long eax, long ds,
-            long es, long fs, long gs, long orig_eax,
-            long eip,long cs,long eflags,long esp,long ss)
-{
-       return -ENOSYS;
-}
index 332e8940d707c7c199e9f7a4797ea2e17bbba305..ee6e07c6c48f21fb1985246a5bf4546bad4cddd6 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -32,7 +31,6 @@
 
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/system.h>
 
 #ifndef SMP
 #define cliIF()
 #endif
 
+/*
+ * Maximum IRQ count.  Currently, this is arbitary.
+ * However, it should not be set too low to prevent
+ * false triggering.  Conversely, if it is set too
+ * high, then you could miss a stuck IRQ.
+ *
+ * Maybe we ought to set a timer and re-enable the
+ * IRQ at a later time?
+ */
+#define MAX_IRQ_CNT    100000
+
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
 spinlock_t irq_controller_lock;
 
+int setup_arm_irq(int, struct irqaction *);
 extern int get_fiq_list(char *);
 extern void init_FIQ(void);
 
@@ -60,16 +70,28 @@ struct irqdesc {
        unsigned int     probing  : 1;          /* IRQ in use for a probe     */
        unsigned int     probe_ok : 1;          /* IRQ can be used for probe  */
        unsigned int     valid    : 1;          /* IRQ claimable              */
-       unsigned int     unused   :26;
+       unsigned int     noautoenable : 1;      /* don't automatically enable IRQ */
+       unsigned int     unused   :25;
        void (*mask_ack)(unsigned int irq);     /* Mask and acknowledge IRQ   */
        void (*mask)(unsigned int irq);         /* Mask IRQ                   */
        void (*unmask)(unsigned int irq);       /* Unmask IRQ                 */
        struct irqaction *action;
-       unsigned int     unused2[3];
+       /*
+        * IRQ lock detection
+        */
+       unsigned int     lck_cnt;
+       unsigned int     lck_pc;
+       unsigned int     lck_jif;
 };
 
 static struct irqdesc irq_desc[NR_IRQS];
 
+/*
+ * Get architecture specific interrupt handlers
+ * and interrupt initialisation.
+ */
+#include <asm/arch/irq.h>
+
 /*
  * Dummy mask/unmask handler
  */
@@ -94,10 +116,12 @@ void enable_irq(unsigned int irq)
 
        spin_lock_irqsave(&irq_controller_lock, flags);
        cliIF();
-       irq_desc[irq].enabled = 1;
        irq_desc[irq].probing = 0;
        irq_desc[irq].triggered = 0;
-       irq_desc[irq].unmask(irq);
+       if (!irq_desc[irq].noautoenable) {
+               irq_desc[irq].enabled = 1;
+               irq_desc[irq].unmask(irq);
+       }
        spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
@@ -119,21 +143,52 @@ int get_irq_list(char *buf)
                *p++ = '\n';
        }
 
-#ifdef CONFIG_ACORN
+#ifdef CONFIG_ARCH_ACORN
        p += get_fiq_list(p);
 #endif
        return p - buf;
 }
 
+/*
+ * IRQ lock detection.
+ *
+ * Hopefully, this should get us out of a few locked situations.
+ * However, it may take a while for this to happen, since we need
+ * a large number if IRQs to appear in the same jiffie with the
+ * same instruction pointer (or within 2 instructions).
+ */
+static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
+{
+       unsigned long instr_ptr = instruction_pointer(regs);
+
+       if (desc->lck_jif == jiffies &&
+           desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) {
+               desc->lck_cnt += 1;
+
+               if (desc->lck_cnt > MAX_IRQ_CNT) {
+                       printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq);
+                       disable_irq(irq);
+               }
+       } else {
+               desc->lck_cnt = 0;
+               desc->lck_pc  = instruction_pointer(regs);
+               desc->lck_jif = jiffies;
+       }
+}
+
 /*
  * do_IRQ handles all normal device IRQ's
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
-       struct irqdesc * desc = irq_desc + irq;
+       struct irqdesc * desc;
        struct irqaction * action;
        int status, cpu;
 
+       irq = fixup_irq(irq);
+
+       desc = irq_desc + irq;
+
        spin_lock(&irq_controller_lock);
        desc->mask_ack(irq);
        spin_unlock(&irq_controller_lock);
@@ -174,6 +229,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
                }
        }
 
+       /*
+        * Debug measure - hopefully we can continue if an
+        * IRQ lockup problem occurs...
+        */
+       check_irq_lock(desc, irq, regs);
+
        irq_exit(cpu, irq);
 
        /*
@@ -181,15 +242,10 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
         * a return code from the irq handler to tell us
         * whether the handler wants us to do software bottom
         * half handling or not..
-        *
-        * ** IMPORTANT NOTE: do_bottom_half() ENABLES IRQS!!! **
-        * **  WE MUST DISABLE THEM AGAIN, ELSE IDE DISKS GO   **
-        * **                       AWOL                       **
         */
        if (1) {
                if (bh_active & bh_mask)
                        do_bottom_half();
-               __cli();
        }
 }
 
@@ -227,11 +283,27 @@ int setup_arm_irq(int irq, struct irqaction * new)
        struct irqaction *old, **p;
        unsigned long flags;
 
-       if (new->flags & SA_SAMPLE_RANDOM)
+       /*
+        * Some drivers like serial.c use request_irq() heavily,
+        * so we have to be careful not to interfere with a
+        * running system.
+        */
+       if (new->flags & SA_SAMPLE_RANDOM) {
+               /*
+                * This function might sleep, we want to call it first,
+                * outside of the atomic block.
+                * Yes, this might clear the entropy pool if the wrong
+                * driver is attempted to be loaded, without actually
+                * installing a new handler, but is this really a problem,
+                * only the sysadmin is able to do this.
+                */
                rand_initialize_irq(irq);
+       }
 
+       /*
+        * The following block of code has to be executed atomically
+        */
        spin_lock_irqsave(&irq_controller_lock, flags);
-
        p = &irq_desc[irq].action;
        if ((old = *p) != NULL) {
                /* Can't share interrupts unless both agree to */
@@ -252,28 +324,24 @@ int setup_arm_irq(int irq, struct irqaction * new)
 
        if (!shared) {
                irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
-               irq_desc[irq].enabled = 1;
                irq_desc[irq].probing = 0;
-               irq_desc[irq].unmask(irq);
+               if (!irq_desc[irq].noautoenable) {
+                       irq_desc[irq].enabled = 1;
+                       irq_desc[irq].unmask(irq);
+               }
        }
 
        spin_unlock_irqrestore(&irq_controller_lock, flags);
        return 0;
 }
 
-/*
- * Using "struct sigaction" is slightly silly, but there
- * are historical reasons and it works well, so..
- */
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                 unsigned long irq_flags, const char * devname, void *dev_id)
 {
        unsigned long retval;
        struct irqaction *action;
 
-       if (!irq_desc[irq].valid)
-               return -EINVAL;
-       if (!handler)
+       if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler)
                return -EINVAL;
 
        action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
@@ -299,28 +367,30 @@ void free_irq(unsigned int irq, void *dev_id)
        struct irqaction * action, **p;
        unsigned long flags;
 
-       if (!irq_desc[irq].valid) {
+       if (irq >= NR_IRQS || !irq_desc[irq].valid) {
                printk(KERN_ERR "Trying to free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
                __backtrace();
 #endif
                return;
        }
+
+       spin_lock_irqsave(&irq_controller_lock, flags);
        for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
                if (action->dev_id != dev_id)
                        continue;
 
                /* Found it - now free it */
-               save_flags_cli (flags);
                *p = action->next;
-               restore_flags (flags);
                kfree(action);
-               return;
+               goto out;
        }
        printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
        __backtrace();
 #endif
+out:
+       spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
 /* Start the interrupt probing.  Unlike other architectures,
@@ -346,7 +416,6 @@ unsigned long probe_irq_on(void)
                        continue;
 
                irq_desc[i].probing = 1;
-               irq_desc[i].enabled = 1;
                irq_desc[i].triggered = 0;
                irq_desc[i].unmask(i);
                irqs += 1;
@@ -364,7 +433,8 @@ unsigned long probe_irq_on(void)
         */
        spin_lock_irq(&irq_controller_lock);
        for (i = 0; i < NR_IRQS; i++) {
-               if (irq_desc[i].probing && irq_desc[i].triggered) {
+               if (irq_desc[i].probing &&
+                   irq_desc[i].triggered) {
                        irq_desc[i].probing = 0;
                        irqs -= 1;
                }
@@ -383,7 +453,7 @@ unsigned long probe_irq_on(void)
 int probe_irq_off(unsigned long irqs)
 {
        unsigned int i;
-       int irq_found = -1;
+       int irq_found = NO_IRQ;
 
        /*
         * look at the interrupts, and find exactly one
@@ -393,7 +463,7 @@ int probe_irq_off(unsigned long irqs)
        for (i = 0; i < NR_IRQS; i++) {
                if (irq_desc[i].probing &&
                    irq_desc[i].triggered) {
-                       if (irq_found != -1) {
+                       if (irq_found != NO_IRQ) {
                                irq_found = NO_IRQ;
                                goto out;
                        }
@@ -405,21 +475,19 @@ int probe_irq_off(unsigned long irqs)
                irq_found = NO_IRQ;
 out:
        spin_unlock_irq(&irq_controller_lock);
+
        return irq_found;
 }
 
-/*
- * Get architecture specific interrupt handlers
- * and interrupt initialisation.
- */
-#include <asm/arch/irq.h>
-
 __initfunc(void init_IRQ(void))
 {
        extern void init_dma(void);
        int irq;
 
        for (irq = 0; irq < NR_IRQS; irq++) {
+               irq_desc[irq].probe_ok = 0;
+               irq_desc[irq].valid    = 0;
+               irq_desc[irq].noautoenable = 0;
                irq_desc[irq].mask_ack = dummy_mask_unmask_irq;
                irq_desc[irq].mask     = dummy_mask_unmask_irq;
                irq_desc[irq].unmask   = dummy_mask_unmask_irq;
index cc2f7a91df55bbb617524feabc206d525c7830c0..eb286347b1ec0f7b2787c511853e1d71875d763c 100644 (file)
@@ -7,11 +7,13 @@
  *
  *  - Red - toggles state every 50 timer interrupts
  */
+#include <linux/module.h>
+
 #include <asm/hardware.h>
 #include <asm/leds.h>
 #include <asm/system.h>
 
-void leds_event(led_event_t ledevt)
+void ebsa110_leds_event(led_event_t ledevt)
 {
        unsigned long flags;
 
@@ -28,3 +30,7 @@ void leds_event(led_event_t ledevt)
 
        restore_flags(flags);
 }
+
+void (*leds_event)(led_event_t) = ebsa110_leds_event;
+
+EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/leds-ebsa285.c b/arch/arm/kernel/leds-ebsa285.c
deleted file mode 100644 (file)
index a8cf2e7..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * arch/arm/kernel/leds-ebsa285.c
- *
- * Copyright (C) 1998 Russell King
- *
- * EBSA-285 LED control routines.  We use the leds as follows:
- *
- *  - Green - toggles state every 50 timer interrupts
- *  - Amber - On if system is not idle
- *  - Red   - currently unused
- */
-#include <asm/hardware.h>
-#include <asm/leds.h>
-#include <asm/system.h>
-
-static char led_state = XBUS_LED_RED | XBUS_LED_GREEN;
-
-void leds_event(led_event_t ledevt)
-{
-       unsigned long flags;
-
-       save_flags_cli(flags);
-
-       switch(ledevt) {
-       case led_idle_start:
-               led_state |= XBUS_LED_AMBER;
-               break;
-
-       case led_idle_end:
-               led_state &= ~XBUS_LED_AMBER;
-               break;
-
-       case led_timer:
-               led_state ^= XBUS_LED_GREEN;
-               break;
-
-       default:
-               break;
-       }
-
-       restore_flags(flags);
-
-       *XBUS_LEDS = led_state;
-}
diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c
new file mode 100644 (file)
index 0000000..cb6c7f4
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * arch/arm/kernel/leds-footbridge.c
+ *
+ * Copyright (C) 1998-1999 Russell King
+ *
+ * EBSA-285 and NetWinder LED control routines.
+ *
+ * The EBSA-285 uses the leds as follows:
+ *  - Green - toggles state every 50 timer interrupts
+ *  - Amber - On if system is not idle
+ *  - Red   - currently unused
+ *
+ * The Netwinder uses the leds as follows:
+ *  - Green - toggles state every 50 timer interrupts
+ *  - Red   - On if the system is not idle
+ *
+ * Changelog:
+ *   02-05-1999        RMK     Various cleanups
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/spinlock.h>
+#include <asm/system.h>
+
+#define LED_STATE_ENABLED      1
+#define LED_STATE_CLAIMED      2
+static char led_state;
+static char hw_led_state;
+
+static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_ARCH_EBSA285
+
+static void __ebsa285_text ebsa285_leds_event(led_event_t evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&leds_lock, flags);
+
+       switch (evt) {
+       case led_start:
+               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN;
+#ifndef CONFIG_LEDS_IDLE
+               hw_led_state |= XBUS_LED_AMBER;
+#endif
+               led_state |= LED_STATE_ENABLED;
+               break;
+
+       case led_stop:
+               led_state &= ~LED_STATE_ENABLED;
+               break;
+
+       case led_claim:
+               led_state |= LED_STATE_CLAIMED;
+               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
+               break;
+
+       case led_release:
+               led_state &= ~LED_STATE_CLAIMED;
+               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
+               break;
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state ^= XBUS_LED_GREEN;
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+       case led_idle_start:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state |= XBUS_LED_RED;
+               break;
+
+       case led_idle_end:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state &= ~XBUS_LED_RED;
+               break;
+#endif
+
+       case led_green_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~XBUS_LED_GREEN;
+               break;
+
+       case led_green_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= XBUS_LED_GREEN;
+               break;
+
+       case led_amber_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~XBUS_LED_AMBER;
+               break;
+
+       case led_amber_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= XBUS_LED_AMBER;
+               break;
+
+       case led_red_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~XBUS_LED_RED;
+               break;
+
+       case led_red_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= XBUS_LED_RED;
+               break;
+
+       default:
+               break;
+       }
+
+       if  (led_state & LED_STATE_ENABLED)
+               *XBUS_LEDS = hw_led_state;
+
+       spin_unlock_irqrestore(&leds_lock, flags);
+}
+
+#endif
+
+#ifdef CONFIG_ARCH_NETWINDER
+
+static void __netwinder_text netwinder_leds_event(led_event_t evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&leds_lock, flags);
+
+       switch (evt) {
+       case led_start:
+               led_state |= LED_STATE_ENABLED;
+               hw_led_state = 0;
+               break;
+
+       case led_stop:
+               led_state &= ~LED_STATE_ENABLED;
+               break;
+
+       case led_claim:
+               led_state |= LED_STATE_CLAIMED;
+               hw_led_state = 0;
+               break;
+
+       case led_release:
+               led_state &= ~LED_STATE_CLAIMED;
+               hw_led_state = 0;
+               break;
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state ^= GPIO_GREEN_LED;
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+       case led_idle_start:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state &= ~GPIO_RED_LED;
+               break;
+
+       case led_idle_end:
+               if (!(led_state & LED_STATE_CLAIMED))
+                       hw_led_state |= GPIO_RED_LED;
+               break;
+#endif
+
+       case led_green_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= GPIO_GREEN_LED;
+               break;
+
+       case led_green_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~GPIO_GREEN_LED;
+               break;
+
+       case led_amber_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED;
+               break;
+
+       case led_amber_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED);
+               break;
+
+       case led_red_on:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state |= GPIO_RED_LED;
+               break;
+
+       case led_red_off:
+               if (led_state & LED_STATE_CLAIMED)
+                       hw_led_state &= ~GPIO_RED_LED;
+               break;
+
+       default:
+               break;
+       }
+
+       spin_unlock_irqrestore(&leds_lock, flags);
+
+       if  (led_state & LED_STATE_ENABLED) {
+               spin_lock_irqsave(&gpio_lock, flags);
+               gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
+               spin_unlock_irqrestore(&gpio_lock, flags);
+       }
+}
+
+#endif
+
+static void dummy_leds_event(led_event_t evt)
+{
+}
+
+__initfunc(void
+init_leds_event(led_event_t evt))
+{
+       switch (machine_arch_type) {
+#ifdef CONFIG_ARCH_EBSA285
+       case MACH_TYPE_EBSA285:
+               leds_event = ebsa285_leds_event;
+               break;
+#endif
+#ifdef CONFIG_ARCH_NETWINDER
+       case MACH_TYPE_NETWINDER:
+               leds_event = netwinder_leds_event;
+               break;
+#endif
+
+       default:
+               leds_event = dummy_leds_event;
+       }
+
+       leds_event(evt);
+}
+
+void (*leds_event)(led_event_t) = init_leds_event;
+
+EXPORT_SYMBOL(leds_event);
index c4674cd35422ecaa5a7bfc5065df25b97ca31a67..a908241d2564186211d6167f96a28bf342f2a58f 100644 (file)
@@ -4,6 +4,7 @@
  * (c) David Alan Gilbert 1995/1996
  */
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
@@ -40,7 +41,7 @@ void oldlatch_bupdate(unsigned char mask,unsigned char newdata)
 }
 #endif
 
-void oldlatch_init(void)
+void __init oldlatch_init(void)
 {
     printk("oldlatch: init\n");
 #ifdef LATCHAADDR
index 6ea02d891be9cef3c10bc6199beb0d4c6ae0a247..68bf5aa1f99620c3bbaea14fa8fdcf5d7a32ef93 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
@@ -55,46 +54,37 @@ void enable_hlt(void)
 }
 
 /*
- * The idle loop on an arm..
+ * The idle loop on an ARM...
  */
 asmlinkage int sys_idle(void)
 {
-       int ret = -EPERM;
-
-       lock_kernel();
        if (current->pid != 0)
-               goto out;
+               return -EPERM;
+
        /* endless idle loop with no priority at all */
-       current->priority = -100;
-       for (;;)
-       {
+       while (1) {
+               if (!current->need_resched && !hlt_counter)
+                       proc_idle();
+               current->policy = SCHED_YIELD;
+               schedule();
+#ifndef CONFIG_NO_PGT_CACHE
                check_pgt_cache();
-#if 0 //def ARCH_IDLE_OK
-               if (!hlt_counter && !current->need_resched)
-                       proc_idle ();
 #endif
-               run_task_queue(&tq_scheduler);
-               schedule();
        }
-       ret = 0;
-out:
-       unlock_kernel();
-       return ret;
 }
 
+static char reboot_mode = 'h';
+
 __initfunc(void reboot_setup(char *str, int *ints))
 {
+       reboot_mode = str[0];
 }
 
-/*
- * This routine reboots the machine by resetting the expansion cards via
- * their loaders, turning off the processor cache (if ARM3), copying the
- * first instruction of the ROM to 0, and executing it there.
- */
 void machine_restart(char * __unused)
 {
-       proc_hard_reset ();
-       arch_hard_reset ();
+       arch_reset(reboot_mode);
+       panic("Reboot failed\n");
+       while (1);
 }
 
 void machine_halt(void)
@@ -149,6 +139,67 @@ void show_regs(struct pt_regs * regs)
 #endif
 }
 
+/*
+ * Task structure and kernel stack allocation.
+ *
+ * Taken from the i386 version.
+ */
+#ifdef CONFIG_CPU_32
+#define EXTRA_TASK_STRUCT      8
+static struct task_struct *task_struct_stack[EXTRA_TASK_STRUCT];
+static int task_struct_stack_ptr = -1;
+#endif
+
+struct task_struct *alloc_task_struct(void)
+{
+       struct task_struct *tsk;
+
+#ifndef EXTRA_TASK_STRUCT
+       tsk = ll_alloc_task_struct();
+#else
+       int index;
+
+       index = task_struct_stack_ptr;
+       if (index >= EXTRA_TASK_STRUCT/2)
+               goto use_cache;
+
+       tsk = ll_alloc_task_struct();
+
+       if (!tsk) {
+               index = task_struct_stack_ptr;
+
+               if (index >= 0) {
+use_cache:             tsk = task_struct_stack[index];
+                       task_struct_stack_ptr = index - 1;
+               }
+       }
+#endif
+#ifdef CONFIG_SYSRQ
+       /* You need this if you want SYSRQ-T to give sensible stack
+        * usage information
+        */
+       if (tsk) {
+               char *p = (char *)tsk;
+               memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
+       }
+#endif
+
+       return tsk;
+}
+
+void free_task_struct(struct task_struct *p)
+{
+#ifdef EXTRA_TASK_STRUCT
+       int index = task_struct_stack_ptr + 1;
+
+       if (index < EXTRA_TASK_STRUCT) {
+               task_struct_stack[index] = p;
+               task_struct_stack_ptr = index;
+       } else
+#endif
+               ll_free_task_struct(p);
+}
+
 /*
  * Free current thread data structures etc..
  */
@@ -179,9 +230,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
        childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1;
        *childregs = *regs;
        childregs->ARM_r0 = 0;
+       childregs->ARM_sp = esp;
 
        save = ((struct context_save_struct *)(childregs)) - 1;
-       copy_thread_css(save);
+       init_thread_css(save);
        p->tss.save = save;
 
        return 0;
@@ -224,3 +276,29 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
        dump->regs = *regs;
        dump->u_fpvalid = dump_fpu (regs, &dump->u_fp);
 }
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+       extern int sys_exit(int) __attribute__((noreturn));
+       pid_t __ret;
+
+       __asm__ __volatile__(
+       "mov    r0, %1          @ kernel_thread sys_clone\n"
+"      mov     r1, #0\n"
+       __syscall(clone)"\n"
+"      mov     %0, r0"
+        : "=r" (__ret)
+        : "Ir" (flags | CLONE_VM) : "r0", "r1");
+       if (__ret == 0)
+               sys_exit((fn)(arg));
+       return __ret;
+}
+
index 5e3bdfe3b9c8b3d67110d46229170103a5deb1cc..fbc3a21874cdb53eb1610475734289a9fbef4cdd 100644 (file)
  */
 static inline long get_stack_long(struct task_struct *task, int offset)
 {
-       unsigned char *stack;
+       struct pt_regs *regs;
 
-       stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-       stack += offset << 2;
-       return *(unsigned long *)stack;
+       regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
+
+       return regs->uregs[offset];
 }
 
 /*
@@ -50,11 +50,12 @@ static inline long get_stack_long(struct task_struct *task, int offset)
 static inline long put_stack_long(struct task_struct *task, int offset,
        unsigned long data)
 {
-       unsigned char *stack;
+       struct pt_regs *regs;
+
+       regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
+
+       regs->uregs[offset] = data;
 
-       stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-       stack += offset << 2;
-       *(unsigned long *) stack = data;
        return 0;
 }
 
@@ -157,11 +158,16 @@ repeat:
        
        if (MAP_NR(page) < max_mapnr) {
                page += addr & ~PAGE_MASK;
+
+               flush_cache_range(vma->vm_mm, addr, addr + sizeof(unsigned long));
+
                *(unsigned long *)page = data;
-               __flush_entry_to_ram(page);
+
+               clean_cache_area(page, sizeof(unsigned long));
+
+               set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+               flush_tlb_page(vma, addr & PAGE_MASK);
        }
-       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-       flush_tlb();
 }
 
 /*
@@ -343,8 +349,7 @@ printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
 printk ("=%08lX ", val);
        return val;
 }
-#undef pc_pointer
-#define pc_pointer(x) ((x) & 0x03fffffc)
+
 int ptrace_set_bpt (struct task_struct *child)
 {
        unsigned long insn, pc, alt;
@@ -651,7 +656,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                return 0;
                        wake_up_process (child);
                        child->exit_code = SIGKILL;
-                       ptrace_cancel_bpt (child);
                        /* make sure single-step breakpoint is gone. */
                        ptrace_cancel_bpt (child);
                        ret = 0;
index cddc3fab3f71db622c39165808d48c93774c4428..0b0a70087ced05e079ae5fabc11cb3597fa50877 100644 (file)
 #define SUPPORT_CPU_SA110
 #endif
 
-#ifndef CONFIG_CMDLINE
-#define CONFIG_CMDLINE "root=/dev/nfs rw"
-#endif
 #define MEM_SIZE       (16*1024*1024)
 #define COMMAND_LINE_SIZE 256
 
+#ifndef CONFIG_CMDLINE
+#define CONFIG_CMDLINE ""
+#endif
+
+extern void reboot_setup(char *str, int *ints);
+extern void fpe_init(void);
+extern void disable_hlt(void);
+
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info = {
  orig_video_lines:     30,
@@ -87,20 +92,26 @@ const struct armversions armidlist[] = {
   /*-- Match -- --- Mask -- -- Manu --  Processor  uname -m   --- ELF STUFF ---
        --- processor asm funcs --- */
 #if defined(CONFIG_CPU_26)
+  /* ARM2 fake ident */
   { 0x41560200, 0xfffffff0, "ARM/VLSI",        "arm2"   , "armv1"  , "v1", 0,
        &arm2_processor_functions   },
+  /* ARM250 fake ident */
   { 0x41560250, 0xfffffff0, "ARM/VLSI",        "arm250" , "armv2"  , "v2", HWCAP_SWP,
        &arm250_processor_functions },
+  /* ARM3 processors */
   { 0x41560300, 0xfffffff0, "ARM/VLSI",        "arm3"   , "armv2"  , "v2", HWCAP_SWP,
        &arm3_processor_functions   },
 #elif defined(CONFIG_CPU_32)
 #ifdef SUPPORT_CPU_ARM6
+  /* ARM6 */
   { 0x41560600, 0xfffffff0, "ARM/VLSI",        "arm6"   , "armv3"  , "v3", HWCAP_SWP,
        &arm6_processor_functions   },
+  /* ARM610 */
   { 0x41560610, 0xfffffff0, "ARM/VLSI",        "arm610" , "armv3"  , "v3", HWCAP_SWP,
        &arm6_processor_functions   },
 #endif
 #ifdef SUPPORT_CPU_ARM7
+  /* ARM7's have a strange numbering */
   { 0x41007000, 0xffffff00, "ARM/VLSI",        "arm7"   , "armv3"  , "v3", HWCAP_SWP,
        &arm7_processor_functions   },
   /* ARM710 IDs are non-standard */
@@ -108,9 +119,15 @@ const struct armversions armidlist[] = {
        &arm7_processor_functions   },
 #endif
 #ifdef SUPPORT_CPU_SA110
-  { 0x4401a100, 0xfffffff0, "DEC",     "sa110"  , "armv4"  , "v3", HWCAP_SWP|HWCAP_HALF,
+#ifdef CONFIG_ARCH_RPC
+  /* Acorn RiscPC's can't handle ARMv4 half-word instructions */
+  { 0x4401a100, 0xfffffff0, "Intel",   "sa110"  , "armv4"  , "v4", HWCAP_SWP,
+       &sa110_processor_functions  },
+#else
+  { 0x4401a100, 0xfffffff0, "Intel",   "sa110"  , "armv4"  , "v4", HWCAP_SWP|HWCAP_HALF,
        &sa110_processor_functions  },
 #endif
+#endif
 #endif
   { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL }
 };
@@ -119,7 +136,7 @@ const struct armversions armidlist[] = {
  * From head-armv.S
  */
 unsigned int processor_id;
-unsigned int machine_type;
+unsigned int __machine_arch_type;
 int armidindex;
 
 extern int root_mountflags;
@@ -131,139 +148,10 @@ extern int _etext, _edata, _end;
  * symbol to be empty if not configured.
  */
 
-/*
- * Risc-PC specific initialisation
- */
-#ifdef CONFIG_ARCH_RPC
-
-#include <asm/arch/mmu.h>
-
-unsigned int vram_half_sam;
-
-static void
-setup_rpc(struct param_struct *params)
-{
-       extern void init_dram_banks(const struct param_struct *params);
-
-       init_dram_banks(params);
-
-       switch (params->u1.s.pages_in_vram) {
-       case 256:
-               vram_half_sam = 1024;
-               break;
-       case 512:
-       default:
-               vram_half_sam = 2048;
-       }
-}
-#else
-#define setup_rpc(x)
-#endif
-
-#ifdef PARAMS_BASE
-
-#ifdef CONFIG_ARCH_ACORN
-int memc_ctrl_reg;
-int number_ide_drives;
-int number_mfm_drives;
-#endif
-
-static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
-
-__initfunc(static char *
-setup_params(unsigned long *mem_end_p))
-{
-       ROOT_DEV          = to_kdev_t(params->u1.s.rootdev);
-       ORIG_X            = params->u1.s.video_x;
-       ORIG_Y            = params->u1.s.video_y;
-       ORIG_VIDEO_COLS   = params->u1.s.video_num_cols;
-       ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
-
-#ifdef CONFIG_ARCH_ACORN
-#ifndef CONFIG_FB
-       {
-               extern int bytes_per_char_h;
-               extern int bytes_per_char_v;
-
-               bytes_per_char_h  = params->u1.s.bytes_per_char_h;
-               bytes_per_char_v  = params->u1.s.bytes_per_char_v;
-       }
-#endif
-       memc_ctrl_reg     = params->u1.s.memc_control_reg;
-       number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3;
-       number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
-
-       setup_rpc(params);
-
-       if (!(params->u1.s.flags & FLAG_READONLY))
-               root_mountflags &= ~MS_RDONLY;
-#endif
-#ifdef CONFIG_BLK_DEV_RAM
-       {
-               extern int rd_doload;
-               extern int rd_prompt;
-               extern int rd_image_start;
-
-               rd_image_start = params->u1.s.rd_start;
-               rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0;
-               rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0;
-       }
-#endif
-
-#ifdef CONFIG_ARCH_ACORN
-       *mem_end_p = GET_MEMORY_END(params);
-#elif defined(CONFIG_ARCH_EBSA285)
-       *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages;
-#else
-       *mem_end_p = PAGE_OFFSET + MEM_SIZE;
-#endif
-
-       return params->commandline;
-}
-
-#else
-
-static char default_command_line[] __initdata = CONFIG_CMDLINE;
-
-__initfunc(static char *
-setup_params(unsigned long *mem_end_p))
-{
-       ROOT_DEV          = 0x00ff;
-
-#ifdef CONFIG_BLK_DEV_RAM
-       {
-               extern int rd_doload;
-               extern int rd_prompt;
-               extern int rd_image_start;
-
-               rd_image_start = 0;
-               rd_prompt = 1;
-               rd_doload = 1;
-       }
-#endif
-
-       *mem_end_p = PAGE_OFFSET + MEM_SIZE;
-
-       return default_command_line;
-}
-#endif
-
 /*
  * initial ram disk
  */
 #ifdef CONFIG_BLK_DEV_INITRD
-__initfunc(static void
-setup_initrd(const struct param_struct *params))
-{
-       if (params->u1.s.initrd_start) {
-               initrd_start = params->u1.s.initrd_start;
-               initrd_end   = initrd_start + params->u1.s.initrd_size;
-       } else {
-               initrd_start = 0;
-               initrd_end   = 0;
-       }
-}
-
 __initfunc(static void
 check_initrd(unsigned long mem_start, unsigned long mem_end))
 {
@@ -276,7 +164,6 @@ check_initrd(unsigned long mem_start, unsigned long mem_end))
 }
 
 #else
-#define setup_initrd(p)
 #define check_initrd(ms,me)
 #endif
 
@@ -289,48 +176,47 @@ setup_processor(void))
               armidlist[armidindex].mask)
                armidindex += 1;
 
-       if (armidlist[armidindex].id == 0) {
-#ifdef CONFIG_ARCH_ACORN
-               int i;
-
-               for (i = 0; i < 3200; i++)
-                       ((unsigned long *)SCREEN2_BASE)[i] = 0x77113322;
-#endif
+       if (armidlist[armidindex].id == 0)
                while (1);
-       }
 
        processor = *armidlist[armidindex].proc;
        processor._proc_init();
 }
 
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
 __initfunc(static void
-setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
+setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz))
 {
-       char c, *to = command_line;
+       char c = ' ', *to = command_line;
        int len = 0;
 
        *mem_start = (unsigned long)&_end;
 
        for (;;) {
-               if (cmd_line[0] == ' ' &&
-                   cmd_line[1] == 'm' &&
-                   cmd_line[2] == 'e' &&
-                   cmd_line[3] == 'm' &&
-                   cmd_line[4] == '=') {
-                       *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0);
-                       switch(*cmd_line) {
-                       case 'M':
-                       case 'm':
-                               *mem_end <<= 10;
-                       case 'K':
-                       case 'k':
-                               *mem_end <<= 10;
+               if (c == ' ') {
+                       if (cmd_line[0] == 'm' &&
+                           cmd_line[1] == 'e' &&
+                           cmd_line[2] == 'm' &&
+                           cmd_line[3] == '=') {
+                               *mem_sz = simple_strtoul(cmd_line+4, &cmd_line, 0);
+                               switch(*cmd_line) {
+                               case 'M':
+                               case 'm':
+                                       *mem_sz <<= 10;
+                               case 'K':
+                               case 'k':
+                                       *mem_sz <<= 10;
+                                       cmd_line++;
+                               }
+                       }
+                       /* if there are two spaces, remove one */
+                       if (*cmd_line == ' ') {
                                cmd_line++;
+                               continue;
                        }
-                       *mem_end = *mem_end + PAGE_OFFSET;
                }
                c = *cmd_line++;
                if (!c)
@@ -341,42 +227,222 @@ setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
        }
 
        *to = '\0';
+
+       /* remove trailing spaces */
+       while (*--to == ' ' && to != command_line)
+               *to = '\0';
+}
+
+__initfunc(static void
+setup_ram(int doload, int prompt, int image_start))
+{
+#ifdef CONFIG_BLK_DEV_RAM
+       extern int rd_doload;
+       extern int rd_prompt;
+       extern int rd_image_start;
+
+       rd_image_start = image_start;
+       rd_prompt = prompt;
+       rd_doload = doload;
+#endif
 }
 
+/*
+ * initial ram disk
+ */
+__initfunc(static void
+setup_initrd(unsigned int start, unsigned int size))
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (start) {
+               initrd_start = start;
+               initrd_end   = start + size;
+       } else {
+               initrd_start = 0;
+               initrd_end   = 0;
+       }
+#endif
+}
+
+#ifdef CONFIG_ARCH_ACORN
+int memc_ctrl_reg;
+int number_mfm_drives;
+unsigned int vram_size;
+#endif
+
+#ifndef PARAMS_BASE
+#define PARAMS_BASE NULL
+#endif
+
+static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
+#define ENDIANNESS ((char)endian_test.l)
+
 __initfunc(void
 setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
+       struct param_struct *params = (struct param_struct *)PARAMS_BASE;
        static unsigned char smptrap;
-       unsigned long memory_end;
-       char endian = 'l';
-       char *from;
+       unsigned long memory_end = 0;
+       char *from = NULL;
 
        if (smptrap == 1)
                return;
        smptrap = 1;
 
+#if defined(CONFIG_ARCH_ARC)
+       __machine_arch_type = MACH_TYPE_ARCHIMEDES;
+#elif defined(CONFIG_ARCH_A5K)
+       __machine_arch_type = MACH_TYPE_A5K;
+#endif
+
        setup_processor();
 
-       from = setup_params(&memory_end);
-       setup_initrd(params);
+       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;
+
+       /*
+        * Add your machine dependencies here
+        */
+       switch (machine_arch_type) {
+       case MACH_TYPE_EBSA110:
+               /* EBSA110 locks if we execute 'wait for interrupt' */
+               disable_hlt();
+               params = NULL;
+               break;
+
+       case MACH_TYPE_EBSA285:
+               if (params) {
+                       ORIG_X           = params->u1.s.video_x;
+                       ORIG_Y           = params->u1.s.video_y;
+                       ORIG_VIDEO_COLS  = params->u1.s.video_num_cols;
+                       ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
+               }
+               break;
+
+       case MACH_TYPE_CO285:
+               {
+#if 0
+                       extern unsigned long boot_memory_end;
+                       extern char boot_command_line[];
+
+                       from = boot_command_line;
+                       memory_end = boot_memory_end;
+#endif
+                       params = NULL;
+               }
+               break;
+
+       case MACH_TYPE_CATS:
+               /* CATS must use soft-reboot */
+               reboot_setup("s", NULL);
+               break;
+
+       case MACH_TYPE_NETWINDER:
+               /*
+                * to be fixed in a future NeTTrom
+                */
+               if (params->u1.s.page_size == 4096) {
+                       if (params->u1.s.nr_pages != 0x2000 &&
+                           params->u1.s.nr_pages != 0x4000) {
+                               printk("Warning: bad NeTTrom parameters detected, using defaults\n");
+                               /*
+                                * This stuff doesn't appear to be initialised
+                                * properly by NeTTrom 2.0.6 and 2.0.7
+                                */
+                               params->u1.s.nr_pages = 0x2000; /* 32MB */
+                               params->u1.s.ramdisk_size = 0;
+                               params->u1.s.flags = FLAG_READONLY;
+                               params->u1.s.initrd_start = 0;
+                               params->u1.s.initrd_size = 0;
+                               params->u1.s.rd_start = 0;
+                               params->u1.s.video_x = 0;
+                               params->u1.s.video_y = 0;
+                               params->u1.s.video_num_cols = 80;
+                               params->u1.s.video_num_rows = 30;
+                       }
+               } else {
+                       printk("Warning: no NeTTrom parameter page detected, using "
+                              "compiled-in settings\n");
+                       params = NULL;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       if (params) {
+               memory_end        = params->u1.s.page_size *
+                                   params->u1.s.nr_pages;
+
+               ROOT_DEV          = to_kdev_t(params->u1.s.rootdev);
+
+               setup_ram((params->u1.s.flags & FLAG_RDLOAD) == 0,
+                         (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+                         params->u1.s.rd_start);
+
+               setup_initrd(params->u1.s.initrd_start,
+                            params->u1.s.initrd_size);
+
+               if (!(params->u1.s.flags & FLAG_READONLY))
+                       root_mountflags &= ~MS_RDONLY;
+
+#ifdef CONFIG_ARCH_ACORN
+#ifdef CONFIG_ARCH_RPC
+               {
+                       extern void init_dram_banks(struct param_struct *);
+                       init_dram_banks(params);
+               }
+#endif
+
+               memc_ctrl_reg     = params->u1.s.memc_control_reg;
+               number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
+               vram_size         = 0;
+
+               switch (params->u1.s.pages_in_vram) {
+               case 512:
+                       vram_size += PAGE_SIZE * 256;
+               case 256:
+                       vram_size += PAGE_SIZE * 256;
+               default:
+                       break;
+               }
+
+               memory_end -= vram_size;
+#endif
+
+               from = params->commandline;
+       } else {
+               ROOT_DEV          = 0x00ff;
+
+               setup_ram(1, 1, 0);
+               setup_initrd(0, 0);
+       }
+
+       if (!memory_end)
+               memory_end = MEM_SIZE;
+
+       if (!from)
+               from = default_command_line;
+
+#ifdef CONFIG_NWFPE
+       fpe_init();
+#endif
 
        /* Save unparsed command line copy for /proc/cmdline */
        memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
        saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
        setup_mem(from, memory_start_p, &memory_end);
-       check_initrd(*memory_start_p, memory_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;
+       memory_end += PAGE_OFFSET;
 
-       *cmdline_p = command_line;
-       *memory_end_p = memory_end;
+       check_initrd(*memory_start_p, memory_end);
 
-       sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, endian);
-       sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, endian);
+       sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, ENDIANNESS);
+       sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, ENDIANNESS);
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
@@ -385,43 +451,26 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem
        conswitchp = &dummy_con;
 #endif
 #endif
+
+       *cmdline_p = command_line;
+       *memory_end_p = memory_end;
 }
 
-static const struct {
-       char *machine_name;
-       char *bus_name;
-} machine_desc[] = {
-       { "DEC-EBSA110",        "DEC"           },
-       { "Acorn-RiscPC",       "Acorn"         },
-       { "Nexus-NexusPCI",     "PCI"           },
-       { "DEC-EBSA285",        "PCI"           },
-       { "Corel-Netwinder",    "PCI/ISA"       },
-       { "Chalice-CATS",       "PCI"           },
-       { "unknown-TBOX",       "PCI"           }
+static const char *machine_desc[] = {
+       "EBSA110",
+       "Acorn-RiscPC",
+       "unknown",
+       "Nexus-FTV/PCI",
+       "EBSA285",
+       "Corel-NetWinder",
+       "Chalice-CATS",
+       "unknown-TBOX",
+       "co-EBSA285",
+       "CL-PS7110",
+       "Acorn-Archimedes",
+       "Acorn-A5000"
 };
 
-#if defined(CONFIG_ARCH_ARC)
-#define HARDWARE "Acorn-Archimedes"
-#define IO_BUS  "Acorn"
-#elif defined(CONFIG_ARCH_A5K)
-#define HARDWARE "Acorn-A5000"
-#define IO_BUS  "Acorn"
-#endif
-
-#if defined(CONFIG_CPU_ARM2)
-#define OPTIMISATION "ARM2"
-#elif defined(CONFIG_CPU_ARM3)
-#define OPTIMISATION "ARM3"
-#elif defined(CONFIG_CPU_ARM6)
-#define OPTIMISATION "ARM6"
-#elif defined(CONFIG_CPU_ARM7)
-#define OPTIMISATION "ARM7"
-#elif defined(CONFIG_CPU_SA110)
-#define OPTIMISATION "StrongARM"
-#else
-#define OPTIMISATION "unknown"
-#endif
-
 int get_cpuinfo(char * buffer)
 {
        int len;
@@ -429,25 +478,12 @@ int get_cpuinfo(char * buffer)
        len = sprintf(buffer,
                "Processor\t: %s %s rev %d\n"
                "BogoMips\t: %lu.%02lu\n"
-               "Hardware\t: %s\n"
-               "Optimisation\t: %s\n"
-               "IO Bus\t\t: %s\n",
+               "Hardware\t: %s\n",
                armidlist[armidindex].manu,
                armidlist[armidindex].name,
                (int)processor_id & 15,
                (loops_per_sec+2500) / 500000,
                ((loops_per_sec+2500) / 5000) % 100,
-#ifdef HARDWARE
-               HARDWARE,
-#else
-               machine_desc[machine_type].machine_name,
-#endif
-               OPTIMISATION,
-#ifdef IO_BUS
-               IO_BUS
-#else
-               machine_desc[machine_type].bus_name
-#endif
-               );
+               machine_desc[machine_arch_type]);
        return len;
 }
index 51e6bcb1737f887e206efa547e30398eb53e6437..5ec48f75285dcd8ccec1768c9aa63892c1c9f9b3 100644 (file)
@@ -28,7 +28,7 @@
 
 asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
                         int options, unsigned long *ru);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
 extern int ptrace_cancel_bpt (struct task_struct *);
 extern int ptrace_set_bpt (struct task_struct *);
 
@@ -50,7 +50,7 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t m
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&saveset, regs))
+               if (do_signal(&saveset, regs, 0))
                        return regs->ARM_r0;
        }
 }
@@ -78,7 +78,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&saveset, regs))
+               if (do_signal(&saveset, regs, 0))
                        return regs->ARM_r0;
        }
 }
@@ -158,12 +158,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 #ifdef CONFIG_CPU_32
        err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr);
 #endif
-       if (!valid_user_regs(regs))
-               return 1;
 
-       /* send SIGTRAP if we're single-stepping */
-       if (ptrace_cancel_bpt (current))
-               send_sig (SIGTRAP, current, 1);
+       err |= !valid_user_regs(regs);
 
        return err;
 }
@@ -173,6 +169,14 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
        struct sigframe *frame;
        sigset_t set;
 
+       /*
+        * Since we stacked the signal on a word boundary,
+        * then 'sp' should be word aligned here.  If it's
+        * not, then the user is trying to mess with us.
+        */
+       if (regs->ARM_sp & 3)
+               goto badframe;
+
        frame = (struct sigframe *)regs->ARM_sp;
 
        if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
@@ -192,6 +196,10 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->sc))
                goto badframe;
 
+       /* Send SIGTRAP if we're single-stepping */
+       if (ptrace_cancel_bpt (current))
+               send_sig(SIGTRAP, current, 1);
+
        return regs->ARM_r0;
 
 badframe:
@@ -204,6 +212,14 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
        struct rt_sigframe *frame;
        sigset_t set;
 
+       /*
+        * Since we stacked the signal on a word boundary,
+        * then 'sp' should be word aligned here.  If it's
+        * not, then the user is trying to mess with us.
+        */
+       if (regs->ARM_sp & 3)
+               goto badframe;
+
        frame = (struct rt_sigframe *)regs->ARM_sp;
 
        if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
@@ -220,6 +236,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
 
+       /* Send SIGTRAP if we're single-stepping */
+       if (ptrace_cancel_bpt (current))
+               send_sig(SIGTRAP, current, 1);
+
        return regs->ARM_r0;
 
 badframe:
@@ -260,6 +280,26 @@ setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/
        return err;
 }
 
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+                                unsigned long framesize)
+{
+       unsigned long sp = regs->ARM_sp;
+
+       /*
+        * This is the X/Open sanctioned signal stack switching.
+        */
+       if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
+               sp = current->sas_ss_sp + current->sas_ss_size;
+
+       /*
+        * No matter what happens, 'sp' must be word
+        * aligned otherwise nasty things could happen
+        */
+       sp &= ~3;
+
+       return (void *)(sp - framesize);
+}
+
 static void setup_frame(int sig, struct k_sigaction *ka,
                        sigset_t *set, struct pt_regs *regs)
 {
@@ -267,9 +307,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        unsigned long retcode;
        int err = 0;
 
-       frame = (struct sigframe *)regs->ARM_sp - 1;
+       frame = get_sigframe(ka, regs, sizeof(*frame));
 
-       if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame)))
+       if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
                goto segv_and_exit;
 
        err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
@@ -286,7 +326,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        } else {
                retcode = (unsigned long)&frame->retcode;
                err |= __put_user(SWI_SYS_SIGRETURN, &frame->retcode);
-               __flush_entry_to_ram (&frame->retcode);
+               flush_icache_range(retcode, retcode + 4);
        }
 
        if (err)
@@ -299,6 +339,11 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        regs->ARM_sp = (unsigned long)frame;
        regs->ARM_lr = retcode;
        regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+       /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+       if (ka->sa.sa_flags & SA_THIRTYTWO)
+               regs->ARM_cpsr = USR_MODE;
+#endif
        if (valid_user_regs(regs))
                return;
 
@@ -315,7 +360,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        unsigned long retcode;
        int err = 0;
 
-       frame = (struct rt_sigframe *)regs->ARM_sp - 1;
+       frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
+
        if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
                goto segv_and_exit;
 
@@ -337,7 +383,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        } else {
                retcode = (unsigned long)&frame->retcode;
                err |= __put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode);
-               __flush_entry_to_ram (&frame->retcode);
+               flush_icache_range(retcode, retcode + 4);
        }
 
        if (err)
@@ -350,6 +396,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->ARM_sp = (unsigned long)frame;
        regs->ARM_lr = retcode;
        regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+       /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+       if (ka->sa.sa_flags & SA_THIRTYTWO)
+               regs->ARM_cpsr = USR_MODE;
+#endif
        if (valid_user_regs(regs))
                return;
 
@@ -393,18 +444,25 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
  * 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(sigset_t *oldset, struct pt_regs *regs)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
 {
-       unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4);
        struct k_sigaction *ka;
        siginfo_t info;
-       int single_stepping, swi_instr;
+       int single_stepping;
+
+       /*
+        * We want the common case to go fast, which
+        * is why we may in certain cases get here from
+        * kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return 0;
 
        if (!oldset)
                oldset = &current->blocked;
 
        single_stepping = ptrace_cancel_bpt (current);
-       swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000);
 
        for (;;) {
                unsigned long signr;
@@ -503,7 +561,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
                }
 
                /* Are we from a system call? */
-               if (swi_instr) {
+               if (syscall) {
                        switch (regs->ARM_r0) {
                        case -ERESTARTNOHAND:
                                regs->ARM_r0 = -EINTR;
@@ -527,7 +585,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
                return 1;
        }
 
-       if (swi_instr &&
+       if (syscall &&
            (regs->ARM_r0 == -ERESTARTNOHAND ||
             regs->ARM_r0 == -ERESTARTSYS ||
             regs->ARM_r0 == -ERESTARTNOINTR)) {
index d50b90f8d6812a91e85c177ef55c25af4e150de5..9da64aad0d1ff80f2efd30c143023147813eb918 100644 (file)
@@ -223,13 +223,7 @@ out:
  */
 asmlinkage int sys_fork(struct pt_regs *regs)
 {
-       int ret;
-
-       lock_kernel();
-       ret = do_fork(SIGCHLD, regs->ARM_sp, regs);
-       unlock_kernel();
-
-       return ret;
+       return do_fork(SIGCHLD, regs->ARM_sp, regs);
 }
 
 /* Clone a task - this clones the calling program thread.
@@ -237,14 +231,14 @@ asmlinkage int sys_fork(struct pt_regs *regs)
  */
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
 {
-       int ret;
-
-       lock_kernel();
        if (!newsp)
                newsp = regs->ARM_sp;
-       ret = do_fork(clone_flags, newsp, regs);
-       unlock_kernel();
-       return ret;
+       return do_fork(clone_flags, newsp, regs);
+}
+
+asmlinkage int sys_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs);
 }
 
 /* sys_execve() executes a new program.
index b6448e9422305045702d996f6abfdcfbf16f2c42..c874a1ba85ba724bd85359d334f1347b2e747fc9 100644 (file)
@@ -129,27 +129,12 @@ void do_settimeofday(struct timeval *tv)
        time_status |= STA_UNSYNC;
        time_maxerror = NTP_PHASE_LIMIT;
        time_esterror = NTP_PHASE_LIMIT;
-       sti ();
+       sti();
 }
 
-/*
- * 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, void *dev_id, struct pt_regs *regs)
-{
-       if (reset_timer ())
-               do_timer(regs);
-
-       update_rtc ();
-}
-
-static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL};
-
 __initfunc(void time_init(void))
 {
-       xtime.tv_sec = setup_timer();
        xtime.tv_usec = 0;
 
-       setup_arm_irq(IRQ_TIMER, &irqtimer);
+       setup_timer();
 }
index 5d04f325bd3f6c4c60f84a185567a84184b6508b..9267fec09214b6f10e0831f358b8c7540cd7c574 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/atomic.h>
 #include <asm/pgtable.h>
 
-extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret);
 extern void c_backtrace (unsigned long fp, int pmode);
 extern int ptrace_cancel_bpt (struct task_struct *);
 
@@ -45,16 +44,17 @@ static inline void console_verbose(void)
 
 int kstack_depth_to_print = 200;
 
-static int verify_stack_pointer (unsigned long stackptr, int size)
+/*
+ * Stack pointers should always be within the kernels view of
+ * physical memory.  If it is not there, then we can't dump
+ * out any information relating to the stack.
+ */
+static int verify_stack(unsigned long sp)
 {
-#ifdef CONFIG_CPU_26
-       if (stackptr < 0x02048000 || stackptr + size > 0x03000000)
-               return -EFAULT;
-#else
-       if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory)
+       if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory)
                return -EFAULT;
-#endif
-               return 0;
+
+       return 0;
 }
 
 /*
@@ -90,22 +90,26 @@ void dump_mem(unsigned long bottom, unsigned long top)
 
 static void dump_instr(unsigned long pc, int user)
 {
-       unsigned long module_start, module_end;
        int pmin = -2, pmax = 3, ok = 0;
        extern char start_kernel, _etext;
 
        if (!user) {
+               unsigned long module_start, module_end;
+               unsigned long kernel_start, kernel_end;
+
                module_start = VMALLOC_START;
                module_end   = module_start + MODULE_RANGE;
 
-               if ((pc >= (unsigned long) &start_kernel) &&
-                   (pc <= (unsigned long) &_etext)) {
-                       if (pc + pmin < (unsigned long) &start_kernel)
-                               pmin = ((unsigned long) &start_kernel) - pc;
-                       if (pc + pmax > (unsigned long) &_etext)
-                               pmax = ((unsigned long) &_etext) - pc;
+               kernel_start = (unsigned long)&start_kernel;
+               kernel_end   = (unsigned long)&_etext;
+
+               if (pc >= kernel_start && pc < kernel_end) {
+                       if (pc + pmin < kernel_start)
+                               pmin = kernel_start - pc;
+                       if (pc + pmax > kernel_end)
+                               pmax = kernel_end - pc;
                        ok = 1;
-               } else if (pc >= module_start && pc <= module_end) {
+               } else if (pc >= module_start && pc < module_end) {
                        if (pc + pmin < module_start)
                                pmin = module_start - pc;
                        if (pc + pmax > module_end)
@@ -125,119 +129,138 @@ static void dump_instr(unsigned long pc, int user)
                printk ("pc not in code space\n");
 }
 
-static void dump_state(char *str, struct pt_regs *regs, int err)
+spinlock_t die_lock;
+
+/*
+ * This function is protected against re-entrancy.
+ */
+void die(const char *str, struct pt_regs *regs, int err)
 {
+       struct task_struct *tsk = current;
+
+       spin_lock_irq(&die_lock);
+
        console_verbose();
        printk("Internal error: %s: %x\n", str, err);
        printk("CPU: %d\n", smp_processor_id());
        show_regs(regs);
        printk("Process %s (pid: %d, stackpage=%08lx)\n",
-               current->comm, current->pid, 4096+(unsigned long)current);
+               current->comm, current->pid, 4096+(unsigned long)tsk);
+
+       if (!user_mode(regs)) {
+               unsigned long sp = (unsigned long)(regs + 1);
+               unsigned long fp;
+               int dump_info = 1;
+
+               printk("Stack: ");
+               if (verify_stack(sp)) {
+                       printk("invalid kernel stack pointer %08lx", sp);
+                       dump_info = 0;
+               } else if (sp < 4096+(unsigned long)tsk)
+                       printk("kernel stack pointer underflow");
+               printk("\n");
+
+               if (dump_info)
+                       dump_mem(sp - 16, 8192+(unsigned long)tsk);
+
+               dump_info = 1;
+
+               printk("Backtrace: ");
+               fp = regs->ARM_fp;
+               if (!fp) {
+                       printk("no frame pointer");
+                       dump_info = 0;
+               } else if (verify_stack(fp)) {
+                       printk("invalid frame pointer %08lx", fp);
+                       dump_info = 0;
+               } else if (fp < 4096+(unsigned long)tsk)
+                       printk("frame pointer underflow");
+               printk("\n");
+
+               if (dump_info)
+                       c_backtrace(fp, processor_mode(regs));
+
+               dump_instr(instruction_pointer(regs), 0);
+       }
+
+       spin_unlock_irq(&die_lock);     
 }
 
-/*
- * This function is protected against kernel-mode re-entrancy.  If it
- * is re-entered it will hang the system since we can't guarantee in
- * this case that any of the functions that it calls are safe any more.
- * Even the panic function could be a problem, but we'll give it a go.
- */
-void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
+static void die_if_kernel(const char *str, struct pt_regs *regs, int err)
 {
-       static int died = 0;
-       unsigned long cstack, sstack, frameptr;
-       
        if (user_mode(regs))
                return;
 
-       switch (died) {
-       case 2:
-               while (1);
-       case 1:
-               died ++;
-               panic ("die_if_kernel re-entered.  Major kernel corruption.  Please reboot me!");
-               break;
-       case 0:
-               died ++;
-               break;
-       }
-
-       dump_state(str, regs, err);
-
-       cstack = (unsigned long)(regs + 1);
-       sstack = 4096+(unsigned long)current;
-
-       printk("Stack: ");
-       if (verify_stack_pointer(cstack, 4))
-               printk("invalid kernel stack pointer %08lx", cstack);
-       else if(cstack > sstack + 4096)
-               printk("(sp overflow)");
-       else if(cstack < sstack)
-               printk("(sp underflow)");
-       printk("\n");
-
-       dump_mem(cstack - 16, sstack + 4096);
-
-       frameptr = regs->ARM_fp;
-       if (frameptr) {
-               if (verify_stack_pointer (frameptr, 4))
-                       printk ("Backtrace: invalid frame pointer\n");
-               else {
-                       printk("Backtrace: \n");
-                       c_backtrace (frameptr, processor_mode(regs));
-               }
-       }
-
-       dump_instr(instruction_pointer(regs), 0);
-       died = 0;
-       if (ret != -1)
-               do_exit (ret);
-       else {
-               cli ();
-               while (1);
-       }
+       die(str, regs, err);
 }
 
-void bad_user_access_alignment (const void *ptr)
+void bad_user_access_alignment(const void *ptr)
 {
-       void *pc;
-       __asm__("mov %0, lr\n": "=r" (pc));
-       printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc);
+       printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, 
+               __builtin_return_address(0));
        current->tss.error_code = 0;
        current->tss.trap_no = 11;
-       force_sig (SIGBUS, current);
-/*     die_if_kernel("Oops - bad user access alignment", regs, mode, SIGBUS);*/
+       force_sig(SIGBUS, current);
+/*     die_if_kernel("Oops - bad user access alignment", regs, mode);*/
 }
 
-asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode)
+asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
 {
+#ifdef CONFIG_DEBUG_USER
+       printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
+               current->comm, current->pid, instruction_pointer(regs));
+#endif
        current->tss.error_code = 0;
        current->tss.trap_no = 6;
-       force_sig (SIGILL, current);
-       die_if_kernel("Oops - undefined instruction", regs, mode, SIGILL);
+       force_sig(SIGILL, current);
+       die_if_kernel("Oops - undefined instruction", regs, mode);
 }
 
-asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode)
+asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
 {
+#ifdef CONFIG_DEBUG_USER
+       printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
+               current->comm, current->pid, instruction_pointer(regs));
+#endif
        current->tss.error_code = 0;
        current->tss.trap_no = 11;
-       force_sig (SIGBUS, current);
-       die_if_kernel("Oops - address exception", regs, mode, SIGBUS);
+       force_sig(SIGBUS, current);
+       die_if_kernel("Oops - address exception", regs, mode);
 }
 
 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
 {
 #ifndef CONFIG_IGNORE_FIQ
-       printk ("Hmm.  Unexpected FIQ received, but trying to continue\n");
-       printk ("You may have a hardware problem...\n");
+       printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
+       printk("You may have a hardware problem...\n");
 #endif
 }
 
+/*
+ * bad_mode handles the impossible case in the vectors.
+ * If you see one of these, then it's extremely serious,
+ * and could mean you have buggy hardware.  It never
+ * returns, and never tries to sync.  We hope that we
+ * can dump out some state information...
+ */
 asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
 {
-       printk (KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
-               handler[reason],
-               processor_modes[proc_mode]);
-       die_if_kernel ("Oops", regs, 0, -1);
+       console_verbose();
+
+       printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
+               handler[reason], processor_modes[proc_mode]);
+
+       /*
+        * Dump out the vectors and stub routines
+        */
+       printk(KERN_CRIT "Vectors:\n");
+       dump_mem(0, 0x40);
+       printk(KERN_CRIT "Stubs:\n");
+       dump_mem(0x200, 0x4b8);
+
+       die("Oops", regs, 0);
+       cli();
+       while(1);
 }
 
 /*
@@ -249,54 +272,85 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
  */
 asmlinkage void math_state_restore (void)
 {
-       current->used_math = 1;
+       current->used_math = 1;
 }
 
-asmlinkage void arm_syscall (int no, struct pt_regs *regs)
+asmlinkage int arm_syscall (int no, struct pt_regs *regs)
 {
        switch (no) {
        case 0: /* branch through 0 */
                force_sig(SIGSEGV, current);
-//             if (user_mode(regs)) {
-//                     dump_state("branch through zero", regs, 0);
-//                     if (regs->ARM_fp)
-//                             c_backtrace (regs->ARM_fp, processor_mode(regs));
-//             }
-               die_if_kernel ("branch through zero", regs, 0, SIGSEGV);
+               die_if_kernel("branch through zero", regs, 0);
                break;
 
        case 1: /* SWI_BREAK_POINT */
                regs->ARM_pc -= 4; /* Decrement PC by one instruction */
-               ptrace_cancel_bpt (current);
-               force_sig (SIGTRAP, current);
+               ptrace_cancel_bpt(current);
+               force_sig(SIGTRAP, current);
+               return regs->ARM_r0;
+
+       case 2: /* sys_cacheflush */
+#ifdef CONFIG_CPU_32
+               /* r0 = start, r1 = length, r2 = flags */
+               processor.u.armv3v4._flush_cache_area(regs->ARM_r0,
+                                                     regs->ARM_r1,
+                                                     1);
+#endif
                break;
 
        default:
-               printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
-               force_sig (SIGILL, current);
+               /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
+                  if not implemented, rather than raising SIGILL.  This
+                  way the calling program can gracefully determine whether
+                  a feature is supported.  */
+               if (no <= 0x7ff)
+                       return -ENOSYS;
+#ifdef CONFIG_DEBUG_USER
+               /* experiance shows that these seem to indicate that
+                * something catastrophic has happened
+                */
+               printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
                if (user_mode(regs)) {
-                       show_regs (regs);
-                       c_backtrace (regs->ARM_fp, processor_mode(regs));
+                       show_regs(regs);
+                       c_backtrace(regs->ARM_fp, processor_mode(regs));
                }
-               die_if_kernel ("Oops", regs, no, SIGILL);
+#endif
+               force_sig(SIGILL, current);
+               die_if_kernel("Oops", regs, no);
                break;
        }
+       return 0;
 }
 
 asmlinkage void deferred(int n, struct pt_regs *regs)
 {
-       dump_state("old system call", regs, n);
-       force_sig (SIGILL, current);
+       /* You might think just testing `handler' would be enough, but PER_LINUX
+        * points it to no_lcall7 to catch undercover SVr4 binaries.  Gutted.
+        */
+       if (current->personality != PER_LINUX && current->exec_domain->handler) {
+               /* Hand it off to iBCS.  The extra parameter and consequent type 
+                * forcing is necessary because of the weird ARM calling convention.
+                */
+               void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler;
+               (*handler)(n, regs);
+               return;
+       }
+
+#ifdef CONFIG_DEBUG_USER
+       printk(KERN_ERR "[%d] %s: old system call.\n", current->pid, 
+              current->comm);
+#endif
+       force_sig(SIGILL, current);
 }
 
 asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
 {
-       printk ("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
+       printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
 }
 
-asmlinkage void arm_invalidptr (const char *function, int size)
+asmlinkage void arm_invalidptr(const char *function, int size)
 {
-       printk ("Invalid pointer size in %s (PC=%p) size %d\n",
+       printk("Invalid pointer size in %s (pc=%p) size %d\n",
                function, __builtin_return_address(0), size);
 }
 
index 684db2a4779999ac360bf5749ce3ac11b7daa60a..0b241d333c301a4f29c0c9cc3bae71a461f7fee5 100644 (file)
@@ -6,14 +6,14 @@
 
 L_TARGET := lib.a
 L_OBJS   := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \
-           system.o string.o uaccess.o
+           semaphore.o string.o system.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
   L_OBJS += uaccess-armo.o
 endif
 
 ifdef CONFIG_ARCH_ACORN
-  L_OBJS += loaders.o ll_char_wr.o io-acorn.o
+  L_OBJS += loaders.o io-acorn.o
   ifdef CONFIG_ARCH_A5K
     L_OBJS += floppydma.o
   endif
@@ -26,12 +26,8 @@ ifeq ($(MACHINE),ebsa110)
   L_OBJS += io-ebsa110.o
 endif
 
-ifeq ($(MACHINE),vnc)
-  L_OBJS += io-ebsa285.o
-endif
-
-ifeq ($(MACHINE),ebsa285)
-  L_OBJS += io-ebsa285.o
+ifeq ($(MACHINE),footbridge)
+  L_OBJS += io-footbridge.o
 endif
 
 include $(TOPDIR)/Rules.make
@@ -45,10 +41,4 @@ getconsdata.o: getconsdata.c
 checksum.o: constants.h
 
 %.o: %.S
-ifneq ($(CONFIG_BINUTILS_NEW),y)
-       $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s
-       $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s
-       $(RM) ..tmp.$<.s
-else
        $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
-endif
index bd5c78d3463f2d9b478b78634508c29d094563cb..daf49fc94c8d9020d0691309feb933e7f2ce6ca3 100644 (file)
@@ -520,13 +520,13 @@ Ldst_aligned:     tst     r0, #3
                LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
                ldr     r4, [r0], #4
                tst     r2, #2
-               beq     Lexit
+               beq     Lexit_r4
                adcs    r3, r3, r4, lsl #16
                strb    r4, [r1], #1
                mov     r4, r4, lsr #8
                strb    r4, [r1], #1
                mov     r4, r4, lsr #8
-               b       Lexit
+               b       Lexit_r4
 
 Ltoo_small:    teq     r2, #0
                LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
@@ -538,10 +538,12 @@ Ltoo_small:       teq     r2, #0
                adds    r3, r3, ip
                strb    ip, [r1], #1
                strb    r8, [r1], #1
-Lexit:         tst     r2, #1
-Ltoo_small1:   ldrneb  ip, [r0], #1
-               strneb  ip, [r1], #1
-               adcnes  r3, r3, ip
+               tst     r2, #1
+Ltoo_small1:   ldrneb  r4, [r0], #1
+Lexit_r4:      tst     r2, #1
+               strneb  r4, [r1], #1
+               andne   r4, r4, #255
+               adcnes  r3, r3, r4
                adcs    r0, r3, #0
                LOADREGS(ea,fp,{r4 - r8, fp, sp, pc})
 
@@ -598,13 +600,13 @@ Lsrc_not_aligned:
                adceq   r0, r3, #0
                LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
                tst     r2, #2
-               beq     Lexit
+               beq     Lexit_r4
                adcs    r3, r3, r4, lsl #16
                strb    r4, [r1], #1
                mov     r4, r4, lsr #8
                strb    r4, [r1], #1
                mov     r4, r4, lsr #8
-               b       Lexit
+               b       Lexit_r4
 
 Lsrc2_aligned: mov     r4, r4, lsr #16
                adds    r3, r3, #0
@@ -650,13 +652,13 @@ Lsrc2_aligned:    mov     r4, r4, lsr #16
                adceq   r0, r3, #0
                LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
                tst     r2, #2
-               beq     Lexit
+               beq     Lexit_r4
                adcs    r3, r3, r4, lsl #16
                strb    r4, [r1], #1
                mov     r4, r4, lsr #8
                strb    r4, [r1], #1
                ldrb    r4, [r0], #1
-               b       Lexit
+               b       Lexit_r4
 
 Lsrc3_aligned: mov     r4, r4, lsr #24
                adds    r3, r3, #0
@@ -702,14 +704,14 @@ Lsrc3_aligned:    mov     r4, r4, lsr #24
                adceq   r0, r3, #0
                LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
                tst     r2, #2
-               beq     Lexit
+               beq     Lexit_r4
                adcs    r3, r3, r4, lsl #16
                strb    r4, [r1], #1
                ldr     r4, [r0], #4
                strb    r4, [r1], #1
                adcs    r3, r3, r4, lsl #24
                mov     r4, r4, lsr #8
-               b       Lexit
+               b       Lexit_r4
 
 ENTRY(__csum_ipv6_magic)
                stmfd   sp!, {lr}
index 08fdccb272f1db2b0695f911eced401b0083348f..778d3e574c6aec80de2bea3edf175b322cf49397 100644 (file)
@@ -26,32 +26,3 @@ ENTRY(floppy_fiqout_start)
                strb    r12, [r11, #-4]
                subs    pc, lr, #4
 SYMBOL_NAME(floppy_fiqout_end):
-
-@ Params:
-@ r0 = length
-@ r1 = address
-@ r2 = floppy port
-@ Puts these into R9_fiq, R10_fiq, R11_fiq
-ENTRY(floppy_fiqsetup)
-               mov     ip, sp
-               stmfd   sp!, {fp, ip, lr, pc}
-               sub     fp, ip, #4
-               MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ)     @ disable FIQs, IRQs, FIQ mode
-               mov     r0, r0
-               mov     r9, r0
-               mov     r10, r1
-               mov     r11, r2
-               RESTOREMODE(r3)                         @ back to normal
-               mov     r0, r0
-               LOADREGS(ea,fp,{fp, sp, pc})
-
-ENTRY(floppy_fiqresidual)
-               mov     ip, sp
-               stmfd   sp!, {fp, ip, lr, pc}
-               sub     fp, ip, #4
-               MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ)     @ disable FIQs, IRQs, FIQ mode
-               mov     r0, r0
-               mov     r0, r9
-               RESTOREMODE(r3)
-               mov     r0, r0
-               LOADREGS(ea,fp,{fp, sp, pc})
index ba145eaff3568c5e915dd400a7d55a7255f7fd61..27f4ca2efc9b3d379c0075482c2ec403cc0f1c34 100644 (file)
@@ -67,6 +67,23 @@ unsigned long PAGE_OLD = _PAGE_OLD;
 unsigned long PAGE_CLEAN = _PAGE_CLEAN;
 #endif
 
+#ifdef PTE_TYPE_SMALL
+unsigned long HPTE_TYPE_SMALL = PTE_TYPE_SMALL;
+unsigned long HPTE_AP_READ    = PTE_AP_READ;
+unsigned long HPTE_AP_WRITE   = PTE_AP_WRITE;
+#endif
+
+#ifdef L_PTE_PRESENT
+unsigned long LPTE_PRESENT    = L_PTE_PRESENT;
+unsigned long LPTE_YOUNG      = L_PTE_YOUNG;
+unsigned long LPTE_BUFFERABLE = L_PTE_BUFFERABLE;
+unsigned long LPTE_CACHEABLE  = L_PTE_CACHEABLE;
+unsigned long LPTE_USER       = L_PTE_USER;
+unsigned long LPTE_WRITE      = L_PTE_WRITE;
+unsigned long LPTE_EXEC       = L_PTE_EXEC;
+unsigned long LPTE_DIRTY      = L_PTE_DIRTY;
+#endif
+
 unsigned long KSWI_BASE = 0x900000;
 unsigned long KSWI_SYS_BASE = 0x9f0000;
 unsigned long SYS_ERROR0 = 0x9f0000;
index 6baa4cd50931c1d3ccba89e6c221e164f53f769b..bf2dd63332f85803c7b0a868a1a69cafaf8d7eee 100644 (file)
                .text
                .align
 
-#define OUT(reg)                                               \
-               mov     r8, reg, lsl $16                        ;\
-               orr     r8, r8, r8, lsr $16                     ;\
-               str     r8, [r3, r0, lsl $2]                    ;\
-               mov     r8, reg, lsr $16                        ;\
-               orr     r8, r8, r8, lsl $16                     ;\
-               str     r8, [r3, r0, lsl $2]
-
-#define IN(reg)                                                        \
-               ldr     reg, [r0]                               ;\
-               and     reg, reg, ip                            ;\
-               ldr     lr, [r0]                                ;\
-               orr     reg, reg, lr, lsl $16
-
-               .equ    pcio_base_high, PCIO_BASE & 0xff000000
-               .equ    pcio_base_low,  PCIO_BASE & 0x00ff0000
-               .equ    io_base_high, IO_BASE & 0xff000000
-               .equ    io_base_low, IO_BASE & 0x00ff0000
-
-               .equ    addr_io_diff_hi, pcio_base_high - io_base_high
-               .equ    addr_io_diff_lo, pcio_base_low - io_base_low
-
-               .macro  addr    reg, off
-               tst     \off, #0x80000000
-               .if     addr_io_diff_hi
-               movne   \reg, #IO_BASE
-               moveq   \reg, #pcio_base_high
-               .if     pcio_base_low
-               addeq   \reg, \reg, #pcio_base_low
-               .endif
-               .else
-               mov     \reg, #IO_BASE
-               addeq   \reg, \reg, #addr_io_diff_lo
-               .endif
+               .equ    diff_pcio_base, PCIO_BASE - IO_BASE
+
+               .macro  outw2   rd
+               mov     r8, \rd, lsl #16
+               orr     r8, r8, r8, lsr #16
+               str     r8, [r3, r0, lsl #2]
+               mov     r8, \rd, lsr #16
+               orr     r8, r8, r8, lsl #16
+               str     r8, [r3, r0, lsl #2]
+               .endm
+
+               .macro  inw2    rd, mask, temp
+               ldr     \rd, [r0]
+               and     \rd, \rd, \mask
+               ldr     \temp, [r0]
+               orr     \rd, \rd, \temp, lsl #16
                .endm
 
-@ Purpose: read a block of data from a hardware register to memory.
-@ Proto  : insw(int from_port, void *to, int len_in_words);
-@ Proto  : inswb(int from_port, void *to, int len_in_bytes);
-@ Notes  : increment to
+               .macro  addr    rd
+               tst     \rd, #0x80000000
+               mov     \rd, \rd, lsl #2
+               add     \rd, \rd, #IO_BASE
+               addeq   \rd, \rd, #diff_pcio_base
+               .endm
+
+.iosw_bad_align_msg:
+               .ascii  "insw: bad buffer alignment (%p), called from %08lX\n\0"
+.iosl_warning:
+               .ascii  "<4>insl/outsl not implemented, called from %08lX\0"
+               .align
+
+/*
+ * These make no sense on Acorn machines.
+ * Print a warning message.
+ */
+ENTRY(insl)
+ENTRY(outsl)
+               adr     r0, .iosl_warning
+               mov     r1, lr
+               b       SYMBOL_NAME(printk)
+
+.iosw_bad_alignment:
+               adr     r0, .iosw_bad_align_msg
+               mov     r2, lr
+               b       SYMBOL_NAME(panic)
+
+
+/* Purpose: read a block of data from a hardware register to memory.
+ * Proto  : void insw(int from_port, void *to, int len_in_words);
+ * Notes  : increment to, 'to' must be 16-bit aligned
+ */
+
+.insw_align:   tst     r1, #1
+               bne     .iosw_bad_alignment
+
+               ldr     r3, [r0]
+               strb    r3, [r1], #1
+               mov     r3, r3, lsr #8
+               strb    r3, [r1], #1
+
+               subs    r2, r2, #1
+               bne     .insw_aligned
 
 ENTRY(insw)
+               teq     r2, #0
+               RETINSTR(moveq,pc,lr)
+               addr    r0
+               tst     r1, #3
+               bne     .insw_align
+
+.insw_aligned: mov     ip, #0xff
+               orr     ip, ip, ip, lsl #8
+               stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .no_insw_8
+
+.insw_8_lp:    ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               ldr     r5, [r0]
+               and     r5, r5, ip
+               ldr     r6, [r0]
+               orr     r5, r5, r6, lsl #16
+
+               ldr     r6, [r0]
+               and     r6, r6, ip
+               ldr     lr, [r0]
+               orr     r6, r6, lr, lsl #16
+
+               stmia   r1!, {r3 - r6}
+               subs    r2, r2, #8
+               bpl     .insw_8_lp
+               tst     r2, #7
+               LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
+
+.no_insw_8:    tst     r2, #4
+               beq     .no_insw_4
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               stmia   r1!, {r3, r4}
+
+.no_insw_4:    tst     r2, #2
+               beq     .no_insw_2
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               str     r3, [r1], #4
+
+.no_insw_2:    tst     r2, #1
+               ldrne   r3, [r0]
+               strneb  r3, [r1], #1
+               movne   r3, r3, lsr #8
+               strneb  r3, [r1]
+               LOADREGS(fd, sp!, {r4, r5, r6, pc})
+
+@ Purpose: write a block of data from memory to a hardware register.
+@ Proto  : outsw(int to_reg, void *from, int len_in_words);
+@ Notes  : increments from
+
+.outsw_align:  tst     r1, #1
+               bne     .iosw_bad_alignment
+
+               add     r1, r1, #2
+
+               ldr     r3, [r1, #-4]
+               mov     r3, r3, lsr #16
+               orr     r3, r3, r3, lsl #16
+               str     r3, [r0]
+               subs    r2, r2, #1
+               bne     .outsw_aligned
+
+ENTRY(outsw)
+               teq     r2, #0
+               RETINSTR(moveq,pc,lr)
+               addr    r0
+               tst     r1, #3
+               bne     .outsw_align
+
+.outsw_aligned:        stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .no_outsw_8
+.outsw_8_lp:   ldmia   r1!, {r3, r4, r5, r6}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               subs    r2, r2, #8
+               bpl     .outsw_8_lp
+               tst     r2, #7
+               LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
+
+.no_outsw_8:   tst     r2, #4
+               beq     .no_outsw_4
+
+               ldmia   r1!, {r3, r4}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.no_outsw_4:   tst     r2, #2
+               beq     .no_outsw_2
+
+               ldr     r3, [r1], #4
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.no_outsw_2:   tst     r2, #1
+
+               ldrne   r3, [r1]
+
+               movne   ip, r3, lsl #16
+               orrne   ip, ip, ip, lsr #16
+               strne   ip, [r0]
+
+               LOADREGS(fd, sp!, {r4, r5, r6, pc})
+
+.insb_align:   rsb     ip, ip, #4
+               cmp     ip, r2
+               movgt   ip, r2
+               cmp     ip, #2
+               ldrb    r3, [r0]
+               strb    r3, [r1], #1
+               ldrgeb  r3, [r0]
+               strgeb  r3, [r1], #1
+               ldrgtb  r3, [r0]
+               strgtb  r3, [r1], #1
+               subs    r2, r2, ip
+               bne     .insb_aligned
+
+ENTRY(insb)
+               teq     r2, #0
+               moveq   pc, lr
+               addr    r0
+               ands    ip, r1, #3
+               bne     .insb_align
+
+.insb_aligned: stmfd   sp!, {r4 - r6, lr}
+
+               subs    r2, r2, #16
+               bmi     .insb_no_16
+
+.insb_16_lp:   ldrb    r3, [r0]
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #8
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #16
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #24
+               ldrb    r4, [r0]
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #8
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #16
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #24
+               ldrb    r5, [r0]
+               ldrb    r6, [r0]
+               orr     r5, r5, r6, lsl #8
+               ldrb    r6, [r0]
+               orr     r5, r5, r6, lsl #16
+               ldrb    r6, [r0]
+               orr     r5, r5, r6, lsl #24
+               ldrb    r6, [r0]
+               ldrb    ip, [r0]
+               orr     r6, r6, ip, lsl #8
+               ldrb    ip, [r0]
+               orr     r6, r6, ip, lsl #16
+               ldrb    ip, [r0]
+               orr     r6, r6, ip, lsl #24
+               stmia   r1!, {r3 - r6}
+               subs    r2, r2, #16
+               bpl     .insb_16_lp
+
+               tst     r2, #15
+               LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+.insb_no_16:   tst     r2, #8
+               beq     .insb_no_8
+
+               ldrb    r3, [r0]
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #8
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #16
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #24
+               ldrb    r4, [r0]
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #8
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #16
+               ldrb    r5, [r0]
+               orr     r4, r4, r5, lsl #24
+               stmia   r1!, {r3, r4}
+
+.insb_no_8:    tst     r2, #4
+               bne     .insb_no_4
+
+               ldrb    r3, [r0]
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #8
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #16
+               ldrb    r4, [r0]
+               orr     r3, r3, r4, lsl #24
+               str     r3, [r1], #4
+
+.insb_no_4:    ands    r2, r2, #3
+               LOADREGS(eqfd, sp!, {r4 - r6, pc})
+               cmp     r2, #2
+               ldrb    r3, [r0]
+               strb    r3, [r1], #1
+               ldrgeb  r3, [r0]
+               strgeb  r3, [r1], #1
+               ldrgtb  r3, [r0]
+               strgtb  r3, [r1]
+               LOADREGS(fd, sp!, {r4 - r6, pc})
+
+
+
+.outsb_align:  rsb     ip, ip, #4
+               cmp     ip, r2
+               mov     ip, r2
+               cmp     ip, #2
+               ldrb    r3, [r1], #1
+               strb    r3, [r0]
+               ldrgeb  r3, [r1], #1
+               strgeb  r3, [r0]
+               ldrgtb  r3, [r1], #1
+               strgtb  r3, [r0]
+               subs    r2, r2, ip
+               bne     .outsb_aligned
+
+ENTRY(outsb)
+               teq     r2, #0
+               moveq   pc, lr
+               addr    r0
+               ands    ip, r1, #3
+               bne     .outsb_align
+
+.outsb_aligned:        stmfd   sp!, {r4 - r6, lr}
+
+               subs    r2, r2, #16
+               bmi     .outsb_no_16
+
+.outsb_16_lp:  ldmia   r1!, {r3 - r6}
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+
+               strb    r5, [r0]
+               mov     r5, r5, lsr #8
+               strb    r5, [r0]
+               mov     r5, r5, lsr #8
+               strb    r5, [r0]
+               mov     r5, r5, lsr #8
+               strb    r5, [r0]
+
+               strb    r6, [r0]
+               mov     r6, r6, lsr #8
+               strb    r6, [r0]
+               mov     r6, r6, lsr #8
+               strb    r6, [r0]
+               mov     r6, r6, lsr #8
+               strb    r6, [r0]
+               subs    r2, r2, #16
+               bpl     .outsb_16_lp
+
+               tst     r2, #15
+               LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+.outsb_no_16:  tst     r2, #8
+               beq     .outsb_no_8
+
+               ldmia   r1, {r3, r4}
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+               mov     r4, r4, lsr #8
+               strb    r4, [r0]
+
+.outsb_no_8:   tst     r2, #4
+               bne     .outsb_no_4
+
+               ldr     r3, [r1], #4
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+               mov     r3, r3, lsr #8
+               strb    r3, [r0]
+
+.outsb_no_4:   ands    r2, r2, #3
+               LOADREGS(eqfd, sp!, {r4 - r6, pc})
+               cmp     r2, #2
+               ldrb    r3, [r1], #1
+               strb    r3, [r0]
+               ldrgeb  r3, [r1], #1
+               strgeb  r3, [r0]
+               ldrgtb  r3, [r1]
+               strgtb  r3, [r0]
+               LOADREGS(fd, sp!, {r4 - r6, pc})
+
+
+
+
+@ Purpose: write a memc register
+@ Proto  : void memc_write(int register, int value);
+@ Returns: nothing
+
+#if defined(CONFIG_CPU_26)
+ENTRY(memc_write)
+               cmp     r0, #7
+               RETINSTR(movgt,pc,lr)
+               mov     r0, r0, lsl #17
+               mov     r1, r1, lsl #15
+               mov     r1, r1, lsr #17
+               orr     r0, r0, r1, lsl #2
+               add     r0, r0, #0x03600000
+               strb    r0, [r0]
+               RETINSTR(mov,pc,lr)
+#define CPSR2SPSR(rt)
+#else
+#define CPSR2SPSR(rt) \
+               mrs     rt, cpsr; \
+               msr     spsr, rt
+#endif
+
+@ Purpose: call an expansion card loader to read bytes.
+@ Proto  : char read_loader(int offset, char *card_base, char *loader);
+@ Returns: byte read
+
+ENTRY(ecard_loader_read)
+               stmfd   sp!, {r4 - r12, lr}
+               mov     r11, r1
+               mov     r1, r0
+               CPSR2SPSR(r0)
+               mov     lr, pc
+               mov     pc, r2
+               LOADREGS(fd, sp!, {r4 - r12, pc})
+
+@ Purpose: call an expansion card loader to reset the card
+@ Proto  : void read_loader(int card_base, char *loader);
+@ Returns: byte read
+
+ENTRY(ecard_loader_reset)
+               stmfd   sp!, {r4 - r12, lr}
+               mov     r11, r0
+               CPSR2SPSR(r0)
+               mov     lr, pc
+               add     pc, r1, #8
+               LOADREGS(fd, sp!, {r4 - r12, pc})
+
+
+#if 0
                mov     r2, r2, lsl#1
-ENTRY(inswb)
                mov     ip, sp
                stmfd   sp!, {r4 - r10, fp, ip, lr, pc}
                sub     fp, ip, #4
@@ -122,14 +586,9 @@ Linsw_notaligned:
                bgt     Linsw_notaligned
                LOADREGS(ea, fp, {r4 - r10, fp, sp, pc})
 
-@ Purpose: write a block of data from memory to a hardware register.
-@ Proto  : outsw(int to_reg, void *from, int len_in_words);
-@ Proto  : outswb(int to_reg, void *from, int len_in_bytes);
-@ Notes  : increments from
 
 ENTRY(outsw)
-               mov     r2, r2, LSL#1
-ENTRY(outswb)
+               mov     r2, r2, lsl#1
                mov     ip, sp
                stmfd   sp!, {r4 - r8, fp, ip, lr, pc}
                sub     fp, ip, #4
@@ -166,56 +625,5 @@ ENTRY(outswb)
                bgt     3b
                LOADREGS(ea, fp, {r4 - r8, fp, sp, pc})
 
-/*
- * These make no sense on Acorn machines atm.
- */
-ENTRY(insl)
-ENTRY(outsl)
-               RETINSTR(mov,pc,lr)
-
-@ Purpose: write a memc register
-@ Proto  : void memc_write(int register, int value);
-@ Returns: nothing
-
-#if defined(CONFIG_CPU_26)
-ENTRY(memc_write)
-               cmp     r0, #7
-               RETINSTR(movgt,pc,lr)
-               mov     r0, r0, lsl #17
-               mov     r1, r1, lsl #15
-               mov     r1, r1, lsr #17
-               orr     r0, r0, r1, lsl #2
-               add     r0, r0, #0x03600000
-               strb    r0, [r0]
-               RETINSTR(mov,pc,lr)
-#define CPSR2SPSR(rt)
-#else
-#define CPSR2SPSR(rt) \
-               mrs     rt, cpsr; \
-               msr     spsr, rt
 #endif
 
-@ Purpose: call an expansion card loader to read bytes.
-@ Proto  : char read_loader(int offset, char *card_base, char *loader);
-@ Returns: byte read
-
-ENTRY(ecard_loader_read)
-               stmfd   sp!, {r4 - r12, lr}
-               mov     r11, r1
-               mov     r1, r0
-               CPSR2SPSR(r0)
-               mov     lr, pc
-               mov     pc, r2
-               LOADREGS(fd, sp!, {r4 - r12, pc})
-
-@ Purpose: call an expansion card loader to reset the card
-@ Proto  : void read_loader(int card_base, char *loader);
-@ Returns: byte read
-
-ENTRY(ecard_loader_reset)
-               stmfd   sp!, {r4 - r12, lr}
-               mov     r11, r0
-               CPSR2SPSR(r0)
-               mov     lr, pc
-               add     pc, r1, #8
-               LOADREGS(fd, sp!, {r4 - r12, pc})
index e0b8229a483a64e208e0983601c7e04fac607e7f..b29276ff767f015cbe71f5b1813851053b3528cc 100644 (file)
                ldr     lr, [r0]                        ;\
                orr     reg, reg, lr, lsl $16
 
+/*
+ * These make no sense on these machines.
+ * Print a warning message.
+ */
+ENTRY(insl)
+ENTRY(outsl)
+ENTRY(insb)
+ENTRY(outsb)
+               adr     r0, io_long_warning
+               mov     r1, lr
+               b       SYMBOL_NAME(printk)
+
+io_long_warning:
+               .ascii  "<4>ins?/outs? not implemented on this architecture\0"
+               .align
+
 @ Purpose: read a block of data from a hardware register to memory.
 @ Proto  : insw(int from_port, void *to, int len_in_words);
 @ Proto  : inswb(int from_port, void *to, int len_in_bytes);
diff --git a/arch/arm/lib/io-ebsa285.S b/arch/arm/lib/io-ebsa285.S
deleted file mode 100644 (file)
index a86983d..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-#include <linux/linkage.h>
-
-ENTRY(insl)
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-               ands    ip, r1, #3
-               bne     2f
-
-1:             ldr     r3, [r0]
-               str     r3, [r1], #4
-               subs    r2, r2, #1
-               bne     1b
-               mov     pc, lr
-
-2:             cmp     ip, #2
-               ldr     ip, [r0]
-               blt     3f
-               bgt     4f
-
-               strh    ip, [r1], #2
-               mov     ip, ip, lsr #16
-1:             subs    r2, r2, #1
-               ldrne   r3, [r0]
-               orrne   ip, ip, r3, lsl #16
-               strne   ip, [r1], #4
-               movne   ip, r3, lsr #16
-               bne     1b
-               strh    ip, [r1], #2
-               mov     pc, lr
-
-3:             strb    ip, [r1], #1
-               mov     ip, ip, lsr #8
-               strh    ip, [r1], #2
-               mov     ip, ip, lsr #16
-1:             subs    r2, r2, #1
-               ldrne   r3, [r0]
-               orrne   ip, ip, r3, lsl #8
-               strne   ip, [r1], #4
-               movne   ip, r3, lsr #24
-               bne     1b
-               strb    ip, [r1], #1
-               mov     pc, lr
-
-4:             strb    ip, [r1], #1
-               mov     ip, ip, lsr #8
-1:             subs    r2, r2, #1
-               ldrne   r3, [r0]
-               orrne   ip, ip, r3, lsl #24
-               strne   ip, [r1], #4
-               movne   ip, r3, lsr #8
-               bne     1b
-               strb    ip, [r1], #1
-               mov     ip, ip, lsr #8
-               strh    ip, [r1], #2
-               mov     pc, lr
-
-ENTRY(outsl)
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-               ands    ip, r1, #3
-               bne     2f
-
-1:             ldr     r3, [r1], #4
-               str     r3, [r0]
-               subs    r2, r2, #1
-               bne     1b
-               mov     pc, lr
-
-2:             bic     r1, r1, #3
-               cmp     ip, #2
-               ldr     ip, [r1], #4
-               mov     ip, ip, lsr #16
-               blt     3f
-               bgt     4f
-
-1:             ldr     r3, [r1], #4
-               orr     ip, ip, r3, lsl #16
-               str     ip, [r0]
-               mov     ip, r3, lsr #16
-               subs    r2, r2, #1
-               bne     1b
-               mov     pc, lr
-
-3:             ldr     r3, [r1], #4
-               orr     ip, ip, r3, lsl #8
-               str     ip, [r0]
-               mov     ip, r3, lsr #24
-               subs    r2, r2, #1
-               bne     3b
-               mov     pc, lr
-
-4:             ldr     r3, [r1], #4
-               orr     ip, ip, r3, lsl #24
-               str     ip, [r0]
-               mov     ip, r3, lsr #8
-               subs    r2, r2, #1
-               bne     4b
-               mov     pc, lr
-
-               /* Nobody could say these are optimal, but not to worry. */
-
-ENTRY(outswb)
-               mov     r2, r2, lsr #1
-ENTRY(outsw)
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-1:             subs    r2, r2, #1
-               ldrgeh  r3, [r1], #2
-               strgeh  r3, [r0]
-               bgt     1b
-               mov     pc, lr
-
-ENTRY(inswb)
-               mov     r2, r2, lsr #1
-ENTRY(insw)
-               stmfd   sp!, {r4, r5, lr}
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-                                               @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17
-               subs    ip, r2, #8
-               blo     too_little
-                                               @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
-               ands    lr, r1, #3              @ check alignment
-               beq     1f
-
-               ldrh    r3, [r0]
-               strh    r3, [r1], #2
-               sub     ip, ip, #1
-               cmn     ip, #8
-               blo     too_little
-
-1:             ldrh    r2, [r0]
-               ldrh    r3, [r0]
-               orr     r2, r2, r3, lsl #16
-               ldrh    r3, [r0]
-               ldrh    r4, [r0]
-               orr     r3, r3, r4, lsl #16
-               ldrh    r4, [r0]
-               ldrh    r5, [r0]
-               orr     r4, r4, r5, lsl #16
-               ldrh    r5, [r0]
-               ldrh    lr, [r0]
-               orr     r5, r5, lr, lsl #16
-               stmia   r1!, {r2, r3, r4, r5}
-               subs    ip, ip, #8
-                                               @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1
-               bhs     1b
-                                               @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7
-               cmn     ip, #4
-               ldrhsh  r2, [r0]                @ ... ... ... ... - 4 - 3 - 2 - 1 ... ...
-               ldrhsh  r3, [r0]
-               orrhs   r2, r2, r3, lsl #16
-               ldrhsh  r3, [r0]
-               ldrhsh  r4, [r0]
-               orrhs   r3, r3, r4, lsl #16
-               stmhsia r1!, {r2, r3}
-
-               tst     ip, #2
-               ldrneh  r2, [r0]                @ ... ... - 6 - 5 ... ... - 2 - 1 ... ...
-               ldrneh  r3, [r0]
-               orrne   r2, r2, r3, lsl #16
-               strne   r2, [r1], #4
-
-               tst     ip, #1
-               ldrneh  r2, [r0]
-               strneh  r2, [r1], #2
-
-               ldmfd   sp!, {r4, r5, pc}
-
-too_little:    subs    r2, r2, #1
-               ldrgeh  r3, [r0]
-               strgeh  r3, [r1], #2
-               bgt     too_little
-
-               ldmfd   sp!, {r4, r5, pc}
-
-
-ENTRY(insb)
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-1:             teq     r2, #0
-               ldrneb  r3, [r0]
-               strneb  r3, [r1], #1
-               subne   r2, r2, #1
-               bne     1b
-               mov     pc, lr
-
-
-ENTRY(outsb)
-               add     r0, r0, #0xff000000
-               add     r0, r0, #0x00e00000
-1:             teq     r2, #0
-               ldrneb  r3, [r1], #1
-               strneb  r3, [r0]
-               subne   r2, r2, #1
-               bne     1b
-               mov     pc, lr
diff --git a/arch/arm/lib/io-footbridge.S b/arch/arm/lib/io-footbridge.S
new file mode 100644 (file)
index 0000000..0734c60
--- /dev/null
@@ -0,0 +1,200 @@
+#include <linux/linkage.h>
+#include <asm/hardware.h>
+
+               .equ    pcio_high, PCIO_BASE & 0xff000000
+               .equ    pcio_low,  PCIO_BASE & 0x00ffffff
+
+               .macro  ioaddr, rd,rn
+               add     \rd, \rn, #pcio_high
+               add     \rd, \rd, #pcio_low
+               .endm
+
+ENTRY(insl)
+               ioaddr  r0, r0
+               ands    ip, r1, #3
+               bne     2f
+
+1:             ldr     r3, [r0]
+               str     r3, [r1], #4
+               subs    r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+2:             cmp     ip, #2
+               ldr     ip, [r0]
+               blt     4f
+               bgt     6f
+
+               strh    ip, [r1], #2
+               mov     ip, ip, lsr #16
+3:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #16
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #16
+               bne     3b
+               strh    ip, [r1], #2
+               mov     pc, lr
+
+4:             strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+               strh    ip, [r1], #2
+               mov     ip, ip, lsr #16
+5:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #8
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #24
+               bne     5b
+               strb    ip, [r1], #1
+               mov     pc, lr
+
+6:             strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+7:             subs    r2, r2, #1
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, lsl #24
+               strne   ip, [r1], #4
+               movne   ip, r3, lsr #8
+               bne     7b
+               strb    ip, [r1], #1
+               mov     ip, ip, lsr #8
+               strh    ip, [r1], #2
+               mov     pc, lr
+
+ENTRY(outsl)
+               ioaddr  r0, r0
+               ands    ip, r1, #3
+               bne     2f
+
+1:             ldr     r3, [r1], #4
+               str     r3, [r0]
+               subs    r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+2:             bic     r1, r1, #3
+               cmp     ip, #2
+               ldr     ip, [r1], #4
+               mov     ip, ip, lsr #16
+               blt     4f
+               bgt     5f
+
+3:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #16
+               str     ip, [r0]
+               mov     ip, r3, lsr #16
+               subs    r2, r2, #1
+               bne     3b
+               mov     pc, lr
+
+4:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #8
+               str     ip, [r0]
+               mov     ip, r3, lsr #24
+               subs    r2, r2, #1
+               bne     4b
+               mov     pc, lr
+
+5:             ldr     r3, [r1], #4
+               orr     ip, ip, r3, lsl #24
+               str     ip, [r0]
+               mov     ip, r3, lsr #8
+               subs    r2, r2, #1
+               bne     5b
+               mov     pc, lr
+
+               /* Nobody could say these are optimal, but not to worry. */
+
+ENTRY(outswb)
+               mov     r2, r2, lsr #1
+ENTRY(outsw)
+               ioaddr  r0, r0
+1:             subs    r2, r2, #1
+               ldrgeh  r3, [r1], #2
+               strgeh  r3, [r0]
+               bgt     1b
+               mov     pc, lr
+
+ENTRY(inswb)
+               mov     r2, r2, lsr #1
+ENTRY(insw)
+               stmfd   sp!, {r4, r5, lr}
+               ioaddr  r0, r0
+                                               @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17
+               subs    ip, r2, #8
+               blo     too_little
+                                               @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
+               ands    lr, r1, #3              @ check alignment
+               beq     1f
+
+               ldrh    r3, [r0]
+               strh    r3, [r1], #2
+               sub     ip, ip, #1
+               cmn     ip, #8
+               blo     too_little
+
+1:             ldrh    r2, [r0]
+               ldrh    r3, [r0]
+               orr     r2, r2, r3, lsl #16
+               ldrh    r3, [r0]
+               ldrh    r4, [r0]
+               orr     r3, r3, r4, lsl #16
+               ldrh    r4, [r0]
+               ldrh    r5, [r0]
+               orr     r4, r4, r5, lsl #16
+               ldrh    r5, [r0]
+               ldrh    lr, [r0]
+               orr     r5, r5, lr, lsl #16
+               stmia   r1!, {r2, r3, r4, r5}
+               subs    ip, ip, #8
+                                               @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1
+               bhs     1b
+                                               @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7
+               cmn     ip, #4
+               ldrhsh  r2, [r0]                @ ... ... ... ... - 4 - 3 - 2 - 1 ... ...
+               ldrhsh  r3, [r0]
+               orrhs   r2, r2, r3, lsl #16
+               ldrhsh  r3, [r0]
+               ldrhsh  r4, [r0]
+               orrhs   r3, r3, r4, lsl #16
+               stmhsia r1!, {r2, r3}
+
+               tst     ip, #2
+               ldrneh  r2, [r0]                @ ... ... - 6 - 5 ... ... - 2 - 1 ... ...
+               ldrneh  r3, [r0]
+               orrne   r2, r2, r3, lsl #16
+               strne   r2, [r1], #4
+
+               tst     ip, #1
+               ldrneh  r2, [r0]
+               strneh  r2, [r1], #2
+
+               ldmfd   sp!, {r4, r5, pc}
+
+too_little:    subs    r2, r2, #1
+               ldrgeh  r3, [r0]
+               strgeh  r3, [r1], #2
+               bgt     too_little
+
+               ldmfd   sp!, {r4, r5, pc}
+
+
+ENTRY(insb)
+               ioaddr  r0, r0
+1:             teq     r2, #0
+               ldrneb  r3, [r0]
+               strneb  r3, [r1], #1
+               subne   r2, r2, #1
+               bne     1b
+               mov     pc, lr
+
+
+ENTRY(outsb)
+               ioaddr  r0, r0
+1:             teq     r2, #0
+               ldrneb  r3, [r1], #1
+               strneb  r3, [r0]
+               subne   r2, r2, #1
+               bne     1b
+               mov     pc, lr
index d018779340974e81e660eb2a01e6f9fa66b333bc..c94a2ba075fbb0b853f569a61c95ab39a8b9bc1a 100644 (file)
@@ -18,7 +18,7 @@ void _memcpy_fromio(void * to, unsigned long from, unsigned long count)
  * Copy data from "real" memory space to IO memory space.
  * This needs to be optimized.
  */
-void _memcpy_toio(unsigned long to, void * from, unsigned long count)
+void _memcpy_toio(unsigned long to, const void * from, unsigned long count)
 {
        while (count) {
                count--;
diff --git a/arch/arm/lib/ll_char_wr.S b/arch/arm/lib/ll_char_wr.S
deleted file mode 100644 (file)
index 966d284..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/arm/lib/ll_char_wr.S
- *
- * Copyright (C) 1995, 1996 Russell King.
- *
- * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
- *
- * 10-04-96    RMK     Various cleanups & reduced register usage.
- * 08-04-98    RMK     Shifts re-ordered
- */
-
-@ Regs: [] = corruptible
-@       {} = used
-@       () = do not use
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-               .text
-
-#define BOLD            0x01
-#define ITALIC          0x02
-#define UNDERLINE       0x04
-#define FLASH           0x08
-#define INVERSE         0x10
-
-LC0:           .word   SYMBOL_NAME(bytes_per_char_h)
-               .word   SYMBOL_NAME(video_size_row)
-               .word   SYMBOL_NAME(cmap_80)
-               .word   SYMBOL_NAME(con_charconvtable)
-
-ENTRY(ll_write_char)
-               stmfd   sp!, {r4 - r7, lr}
-@
-@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
-@
-               eor     ip, r1, #UNDERLINE << 9
-/*
- * calculate colours
- */
-               tst     r1, #INVERSE << 9
-               moveq   r2, r1, lsr #16
-               moveq   r3, r1, lsr #24
-               movne   r2, r1, lsr #24
-               movne   r3, r1, lsr #16
-               and     r3, r3, #255
-               and     r2, r2, #255
-/*
- * calculate offset into character table
- */
-               mov     r1, r1, lsl #23
-               mov     r1, r1, lsr #20
-/*
- * calculate offset required for each row [maybe I should make this an argument to this fn.
- * Have to see what the register usage is like in the calling routines.
- */
-               adr     r4, LC0
-               ldmia   r4, {r4, r5, r6, lr}
-               ldr     r4, [r4]
-               ldr     r5, [r5]
-/*
- * Go to resolution-dependent routine...
- */
-               cmp     r4, #4
-               blt     Lrow1bpp
-               eor     r2, r3, r2                      @ Create eor mask to change colour from bg
-               orr     r3, r3, r3, lsl #8              @ to fg.
-               orr     r3, r3, r3, lsl #16
-               add     r0, r0, r5, lsl #3              @ Move to bottom of character
-               add     r1, r1, #7
-               ldrb    r7, [r6, r1]
-               tst     ip, #UNDERLINE << 9
-               eoreq   r7, r7, #255
-               teq     r4, #8
-               beq     Lrow8bpplp
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
-@
-               orr     r3, r3, r3, lsl #4
-Lrow4bpplp:    ldr     r7, [lr, r7, lsl #2]
-               mul     r7, r2, r7
-               tst     r1, #7                          @ avoid using r7 directly after
-               eor     ip, r3, r7
-               str     ip, [r0, -r5]!
-               LOADREGS(eqfd, sp!, {r4 - r7, pc})
-               sub     r1, r1, #1
-               ldrb    r7, [r6, r1]
-               ldr     r7, [lr, r7, lsl #2]
-               mul     r7, r2, r7
-               tst     r1, #7                          @ avoid using r7 directly after
-               eor     ip, r3, r7
-               str     ip, [r0, -r5]!
-               subne   r1, r1, #1
-               ldrneb  r7, [r6, r1]
-               bne     Lrow4bpplp
-               LOADREGS(fd, sp!, {r4 - r7, pc})
-
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
-@
-Lrow8bpplp:    mov     ip, r7, lsr #4
-               ldr     ip, [lr, ip, lsl #2]
-               mul     r4, r2, ip
-               and     ip, r7, #15                     @ avoid r4
-               ldr     ip, [lr, ip, lsl #2]            @ avoid r4
-               mul     ip, r2, ip                      @ avoid r4
-               eor     r4, r3, r4                      @ avoid ip
-               tst     r1, #7                          @ avoid ip
-               sub     r0, r0, r5                      @ avoid ip
-               eor     ip, r3, ip
-               stmia   r0, {r4, ip}
-               LOADREGS(eqfd, sp!, {r4 - r7, pc})
-               sub     r1, r1, #1
-               ldrb    r7, [r6, r1]
-               mov     ip, r7, lsr #4
-               ldr     ip, [lr, ip, lsl #2]
-               mul     r4, r2, ip
-               and     ip, r7, #15                     @ avoid r4
-               ldr     ip, [lr, ip, lsl #2]            @ avoid r4
-               mul     ip, r2, ip                      @ avoid r4
-               eor     r4, r3, r4                      @ avoid ip
-               tst     r1, #7                          @ avoid ip
-               sub     r0, r0, r5                      @ avoid ip
-               eor     ip, r3, ip
-               stmia   r0, {r4, ip}
-               subne   r1, r1, #1
-               ldrneb  r7, [r6, r1]
-               bne     Lrow8bpplp
-               LOADREGS(fd, sp!, {r4 - r7, pc})
-
-@
-@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc)
-@
-Lrow1bpp:      add     r6, r6, r1
-               ldmia   r6, {r4, r7}
-               tst     ip, #INVERSE << 9
-               mvnne   r4, r4
-               mvnne   r7, r7
-               strb    r4, [r0], r5
-               mov     r4, r4, lsr #8
-               strb    r4, [r0], r5
-               mov     r4, r4, lsr #8
-               strb    r4, [r0], r5
-               mov     r4, r4, lsr #8
-               strb    r4, [r0], r5
-               strb    r7, [r0], r5
-               mov     r7, r7, lsr #8
-               strb    r7, [r0], r5
-               mov     r7, r7, lsr #8
-               strb    r7, [r0], r5
-               mov     r7, r7, lsr #8
-               tst     ip, #UNDERLINE << 9
-               mvneq   r7, r7
-               strb    r7, [r0], r5
-               LOADREGS(fd, sp!, {r4 - r7, pc})
-
-               .bss
-ENTRY(con_charconvtable)
-               .space  1024
diff --git a/arch/arm/lib/semaphore.S b/arch/arm/lib/semaphore.S
new file mode 100644 (file)
index 0000000..778fafc
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  linux/arch/arm/lib/semaphore.S
+ *
+ *  Idea from i386 code, Copyright Linus Torvalds.
+ *  Converted for ARM by Russell King
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * The semaphore operations have a special calling sequence
+ * that allows us to keep the distruption of the main code
+ * path to a minimum.  These routines save and restore the
+ * registers that will be touched by __down etc.
+ */
+ENTRY(__down_failed)
+       stmfd   sp!, {r0 - r3, ip, lr}
+       bl      SYMBOL_NAME(__down)
+       LOADREGS(fd, sp!, {r0 - r3, ip, pc})
+
+ENTRY(__down_interruptible_failed)
+       stmfd   sp!, {r1 - r3, ip, lr}
+       bl      SYMBOL_NAME(__down_interruptible)
+       LOADREGS(fd, sp!, {r1 - r3, ip, pc})
+
+ENTRY(__down_trylock_failed)
+       stmfd   sp!, {r1 - r3, ip, lr}
+       bl      SYMBOL_NAME(__down_trylock)
+       LOADREGS(fd, sp!, {r1 - r3, ip, pc})
+
+ENTRY(__up_wakeup)
+       stmfd   sp!, {r0 - r3, ip, lr}
+       bl      SYMBOL_NAME(__up)
+       LOADREGS(fd, sp!, {r0 - r3, ip, pc})
index 810dea6993090b6b3cfd7501e87e86c877ee45e9..1251525dac59a358b32b3c2760f188fd0de1c899 100644 (file)
@@ -26,25 +26,14 @@ void __bad_pmd_kernel(pmd_t *pmd)
        set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
 }
 
-static void
-kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
-                 struct task_struct *tsk, struct mm_struct *mm)
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+void show_pte(struct mm_struct *mm, unsigned long addr)
 {
-       char *reason;
-       /*
-        * Oops. The kernel tried to access some bad page. We'll have to
-        * terminate things with extreme prejudice.
-        */
        pgd_t *pgd;
 
-       if (addr < PAGE_SIZE)
-               reason = "NULL pointer dereference";
-       else
-               reason = "paging request";
-
-       printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
-               reason, addr);
-       printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
        pgd = pgd_offset(mm, addr);
        printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
 
@@ -77,6 +66,27 @@ kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
        } while(0);
 
        printk("\n");
+}
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+static void
+kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
+                 struct task_struct *tsk, struct mm_struct *mm)
+{
+       char *reason;
+
+       if (addr < PAGE_SIZE)
+               reason = "NULL pointer dereference";
+       else
+               reason = "paging request";
+
+       printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
+               reason, addr);
+       printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
+       show_pte(mm, addr);
        die("Oops", regs, mode);
 
        do_exit(SIGKILL);
index 70d7c77b9a5a5e7c905880b4fd02202fa7ff0074..48e34214e7375cd2ac532e6dcd96d8d91d1ec9cd 100644 (file)
@@ -115,19 +115,19 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
 {
        void * addr;
        struct vm_struct * area;
-       unsigned long offset;
+       unsigned long offset, last_addr;
+
+       /* Don't allow wraparound or zero size */
+       last_addr = phys_addr + size - 1;
+       if (!size || last_addr < phys_addr)
+               return NULL;
 
        /*
         * Mappings have to be page-aligned
         */
        offset = phys_addr & ~PAGE_MASK;
-       size = PAGE_ALIGN(size + offset);
-
-       /*
-        * Don't allow mappings that wrap..
-        */
-       if (!size || size > phys_addr + size)
-               return NULL;
+       phys_addr &= PAGE_MASK;
+       size = PAGE_ALIGN(last_addr) - phys_addr;
 
        /*
         * Ok, go for it..
index 263d79708f478602947995bc554c137cf4ead040..7e4871fe2a79720bde91ddc4872e40b00a782382 100644 (file)
@@ -202,15 +202,11 @@ _arm2_3_check_bugs:
 LC0:           .word   SYMBOL_NAME(page_nr)
 /*
  * Function: arm2_switch_to (struct task_struct *prev, struct task_struct *next)
- *
  * Params  : prev      Old task structure
  *        : next       New task structure for process to run
- *
  * Returns : prev
- *
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *          the new.
- *
  * Notes   : We don't fiddle with the FP registers here - we postpone this until
  *          the new task actually uses FP.  This way, we don't swap FP for tasks
  *          that do not require it.
@@ -316,15 +312,11 @@ _arm2_proc_init:
 _arm2_proc_fin:        movs    pc, lr
 /*
  * Function: arm3_switch_to (struct task_struct *prev, struct task_struct *next)
- *
  * Params  : prev      Old task structure
  *        : next       New task structure for process to run
- *
  * Returns : prev
- *
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *          the new.
- *
  * Notes   : We don't fiddle with the FP registers here - we postpone this until
  *          the new task actually uses FP.  This way, we don't swap FP for tasks
  *          that do not require it.
index b817ae2b4c37e4ce052f4187b1acf816d3d41919..d1f31e35d0aa0d9667b864d8c9aadaebf1b5ced3 100644 (file)
@@ -74,14 +74,14 @@ _arm6_7_switch_to:
                str     sp, [r0, #TSS_SAVE]             @ Save sp_SVC
                ldr     sp, [r1, #TSS_SAVE]             @ Get saved sp_SVC
                ldr     r2, [r1, #TSK_ADDR_LIMIT]
+               ldr     r3, [r1, #TSS_MEMMAP]           @ Page table pointer
                teq     r2, #0
                moveq   r2, #DOM_KERNELDOMAIN
                movne   r2, #DOM_USERDOMAIN
                mcr     p15, 0, r2, c3, c0              @ Set domain reg
-               ldr     r2, [r1, #TSS_MEMMAP]           @ Page table pointer
                mov     r1, #0
                mcr     p15, 0, r1, c7, c0, 0           @ flush cache
-               mcr     p15, 0, r2, c2, c0, 0           @ update page table ptr
+               mcr     p15, 0, r3, c2, c0, 0           @ update page table ptr
                mcr     p15, 0, r1, c5, c0, 0           @ flush TLBs
                ldmfd   sp!, {ip}
                msr     spsr, ip                        @ Save tasks CPSR into SPSR for this return
index ff55c8ffa170ad596ce4a309472e0e8fca1a4cd8..be9fad45e5ab756fd99196d93f4e51ac40893c69 100644 (file)
@@ -29,11 +29,11 @@ _sa110_flush_cache_all:                                     @ preserves r0
                mov     r2, #1
 _sa110_flush_cache_all_r2:
                ldr     r3, =Lclean_switch
+               ldr     ip, =FLUSH_BASE
                ldr     r1, [r3]
                ands    r1, r1, #1
                eor     r1, r1, #1
                str     r1, [r3]
-               ldr     ip, =FLUSH_BASE
                addne   ip, ip, #32768
                add     r1, ip, #16384                  @ only necessary for 16k
 1:             ldr     r3, [ip], #32
@@ -226,12 +226,12 @@ _sa110_switch_to:
                ldr     r2, [r0, #TSS_MEMMAP]           @ Get old page tables
                str     sp, [r0, #TSS_SAVE]             @ Save sp_SVC
                ldr     sp, [r1, #TSS_SAVE]             @ Get saved sp_SVC
-               ldr     r4, [r1, #TSK_ADDR_LIMIT]
-               teq     r4, #0
-               moveq   r4, #DOM_KERNELDOMAIN
-               movne   r4, #DOM_USERDOMAIN
-               mcr     p15, 0, r4, c3, c0              @ Set segment
+               ldr     r5, [r1, #TSK_ADDR_LIMIT]
                ldr     r4, [r1, #TSS_MEMMAP]           @ Page table pointer
+               teq     r5, #0
+               moveq   r5, #DOM_KERNELDOMAIN
+               movne   r5, #DOM_USERDOMAIN
+               mcr     p15, 0, r5, c3, c0              @ Set segment
 /*
  * Flushing the cache is nightmarishly slow, so we take any excuse
  * to get out of it.  If the old page table is the same as the new,
@@ -288,7 +288,8 @@ _sa110_data_abort:
  */
                .align  5
 _sa110_set_pmd:        str     r1, [r0]
-               mcr     p15, 0, r0, c7, c10, 1          @ clean D entry  (drain is done by TLB fns)
+               mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+               mcr     p15, 0, r0, c7, c10, 4          @ drain WB (TLB bypasses WB)
                mov     pc, lr
 
 /*
@@ -318,6 +319,7 @@ _sa110_set_pte:     str     r1, [r0], #-1024                @ linux version
                str     r2, [r0]                        @ hardware version
                mov     r0, r0
                mcr     p15, 0, r0, c7, c10, 1          @ clean D entry  (drain is done by TLB fns)
+               mcr     p15, 0, r0, c7, c10, 4          @ drain WB (TLB bypasses WB)
                mov     pc, lr
 
 /*
diff --git a/arch/arm/nwfpe/ARM-gcc.h b/arch/arm/nwfpe/ARM-gcc.h
new file mode 100644 (file)
index 0000000..d726aa4
--- /dev/null
@@ -0,0 +1,128 @@
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define LITTLEENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified.  For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits.  The `flag' type must be able to hold either a 0 or 1.  For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef char flag;
+typedef unsigned char uint8;
+typedef signed char int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified.  For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and if
+necessary ``marks'' the literal as having a 64-bit integer type.  For
+example, the Gnu C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type.  Some compilers may allow `LIT64' to be
+defined as the identity macro:  `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined.  If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE extern __inline__
+
+
+/* For use as a GCC soft-float library we need some special function names. */
+
+#ifdef __LIBFLOAT__
+
+/* Some 32-bit ops can be mapped straight across by just changing the name. */
+#define float32_add                    __addsf3
+#define float32_sub                    __subsf3
+#define float32_mul                    __mulsf3
+#define float32_div                    __divsf3
+#define int32_to_float32               __floatsisf
+#define float32_to_int32_round_to_zero __fixsfsi
+#define float32_to_uint32_round_to_zero        __fixunssfsi
+
+/* These ones go through the glue code.  To avoid namespace pollution
+   we rename the internal functions too.  */
+#define float32_eq                     ___float32_eq
+#define float32_le                     ___float32_le
+#define float32_lt                     ___float32_lt
+
+/* All the 64-bit ops have to go through the glue, so we pull the same
+   trick.  */
+#define float64_add                    ___float64_add
+#define float64_sub                    ___float64_sub
+#define float64_mul                    ___float64_mul
+#define float64_div                    ___float64_div
+#define int32_to_float64               ___int32_to_float64
+#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero
+#define float64_to_uint32_round_to_zero        ___float64_to_uint32_round_to_zero
+#define float64_to_float32             ___float64_to_float32
+#define float32_to_float64             ___float32_to_float64
+#define float64_eq                     ___float64_eq
+#define float64_le                     ___float64_le
+#define float64_lt                     ___float64_lt
+
+#if 0
+#define float64_add                    __adddf3
+#define float64_sub                    __subdf3
+#define float64_mul                    __muldf3
+#define float64_div                    __divdf3
+#define int32_to_float64               __floatsidf
+#define float64_to_int32_round_to_zero __fixdfsi
+#define float64_to_uint32_round_to_zero        __fixunsdfsi
+#define float64_to_float32             __truncdfsf2
+#define float32_to_float64             __extendsfdf2
+#endif
+
+#endif
diff --git a/arch/arm/nwfpe/ChangeLog b/arch/arm/nwfpe/ChangeLog
new file mode 100644 (file)
index 0000000..e160d36
--- /dev/null
@@ -0,0 +1,20 @@
+1998-11-23  Scott Bambrough  <scottb@corelcomputer.com>
+
+       * README.FPE - fix typo in description of lfm/sfm instructions
+       * NOTES - Added file to describe known bugs/problems 
+       * fpmodule.c - Changed version number to 0.94
+
+1998-11-20  Scott Bambrough  <scottb@corelcomputer.com>
+
+       * README.FPE - fix description of URD, NRM instructions
+       * TODO - remove URD, NRM instructions from TODO list
+       * single_cpdo.c - implement URD, NRM
+       * double_cpdo.c - implement URD, NRM
+       * extended_cpdo.c - implement URD, NRM
+
+1998-11-19  Scott Bambrough  <scottb@corelcomputer.com>
+
+       * ChangeLog - Added this file to track changes made.
+       * fpa11.c - added code to initialize register types to typeNone
+       * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to
+         typeDouble in switch statement)
diff --git a/arch/arm/nwfpe/Makefile b/arch/arm/nwfpe/Makefile
new file mode 100644 (file)
index 0000000..5db79c6
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# linux/arch/arm/nwfpe/Makefile
+#
+# Copyright (C) 1998, 1999 Philip Blundell
+#
+
+NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
+             fpmodule.o fpopcode.o softfloat.o \
+             single_cpdo.o double_cpdo.o extended_cpdo.o
+
+ifeq ($(CONFIG_CPU_26),y)
+NWFPE_OBJS += entry26.o
+else
+NWFPE_OBJS += entry.o
+endif
+
+L_TARGET := math-emu.a
+
+ifeq ($(CONFIG_NWFPE),y)
+L_OBJS = $(NWFPE_OBJS)
+else
+  ifeq ($(CONFIG_NWFPE),m)
+    M_OBJS = nwfpe.o
+    MI_OBJS = $(NWFPE_OBJS)
+  endif
+endif    
+
+include $(TOPDIR)/Rules.make
+
+nwfpe.o: $(MI_OBJS) $(MIX_OBJS)
+        $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
diff --git a/arch/arm/nwfpe/config.h b/arch/arm/nwfpe/config.h
new file mode 100644 (file)
index 0000000..35f9d63
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#if 1
+#define C_SYMBOL_NAME(foo)     foo
+#else
+#define C_SYMBOL_NAME(foo)     _##foo
+#endif
+
+#endif
diff --git a/arch/arm/nwfpe/double_cpdo.c b/arch/arm/nwfpe/double_cpdo.c
new file mode 100644 (file)
index 0000000..e746c7a
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+extern FPA11 *fpa11;
+
+float64 getDoubleConstant(unsigned int);
+
+float64 float64_exp(float64 Fm);
+float64 float64_ln(float64 Fm);
+float64 float64_sin(float64 rFm);
+float64 float64_cos(float64 rFm);
+float64 float64_arcsin(float64 rFm);
+float64 float64_arctan(float64 rFm);
+float64 float64_log(float64 rFm);
+float64 float64_tan(float64 rFm);
+float64 float64_arccos(float64 rFm);
+float64 float64_pow(float64 rFn,float64 rFm);
+float64 float64_pol(float64 rFn,float64 rFm);
+
+unsigned int DoubleCPDO(const unsigned int opcode)
+{
+   float64 rFm, rFn;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   //fp_printk("DoubleCPDO(0x%08x)\n",opcode);
+   
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getDoubleConstant(Fm);
+   }
+   else
+   {  
+     switch (fpa11->fpreg[Fm].fType)
+     {
+        case typeSingle:
+          rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle);
+        break;
+
+        case typeDouble:
+          rFm = fpa11->fpreg[Fm].fValue.fDouble;
+          break;
+
+        case typeExtended:
+            // !! patb
+           //fp_printk("not implemented! why not?\n");
+            //!! ScottB
+            // should never get here, if extended involved
+            // then other operand should be promoted then
+            // ExtendedCPDO called.
+            break;
+
+        default: return 0;
+     }
+   }
+
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fpreg[Fn].fType)
+      {
+        case typeSingle:
+          rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+        break;
+
+        case typeDouble:
+          rFn = fpa11->fpreg[Fn].fValue.fDouble;
+        break;
+        
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm);
+      break;
+
+   case SUF_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+      break;
+
+      case MNF_CODE:
+      {
+         unsigned int *p = (unsigned int*)&rFm;
+         p[1] ^= 0x80000000;
+         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+      }
+      break;
+
+      case ABS_CODE:
+      {
+         unsigned int *p = (unsigned int*)&rFm;
+         p[1] &= 0x7fffffff;
+         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+      }
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = 
+             int32_to_float64(float64_to_int32(rFm));
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+      
+      default:
+      {
+        nRc = 0;
+      }
+   }
+
+   if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble;
+   return nRc;
+}
+
+#if 0
+float64 float64_exp(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_ln(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_sin(float64 rFm)
+{
+  return rFm;
+//series
+}
+
+float64 float64_cos(float64 rFm)
+{
+   return rFm;
+   //series
+}
+
+#if 0
+float64 float64_arcsin(float64 rFm)
+{
+//series
+}
+
+float64 float64_arctan(float64 rFm)
+{
+  //series
+}
+#endif
+
+float64 float64_log(float64 rFm)
+{
+  return float64_div(float64_ln(rFm),getDoubleConstant(7));
+}
+
+float64 float64_tan(float64 rFm)
+{
+  return float64_div(float64_sin(rFm),float64_cos(rFm));
+}
+
+float64 float64_arccos(float64 rFm)
+{
+return rFm;
+   //return float64_sub(halfPi,float64_arcsin(rFm));
+}
+
+float64 float64_pow(float64 rFn,float64 rFm)
+{
+  return float64_exp(float64_mul(rFm,float64_ln(rFn))); 
+}
+
+float64 float64_pol(float64 rFn,float64 rFm)
+{
+  return float64_arctan(float64_div(rFn,rFm)); 
+}
+#endif
diff --git a/arch/arm/nwfpe/entry.S b/arch/arm/nwfpe/entry.S
new file mode 100644 (file)
index 0000000..6f0077f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    (c) Philip Blundell 1998-1999
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This is the kernel's entry point into the floating point emulator.
+It is called from the kernel with code similar to this:
+
+       adrsvc  al, r9, ret_from_exception      @ r9  = normal FP return
+       adrsvc  al, lr, fpundefinstr            @ lr  = undefined instr return
+
+       get_current_task r10
+       mov     r8, #1
+       strb    r8, [r10, #TSK_USED_MATH]       @ set current->used_math
+       add     r10, r10, #TSS_FPESAVE          @ r10 = workspace
+       ldr     r4, .LC2
+       ldr     pc, [r4]                        @ Call FP emulator entry point
+
+The kernel expects the emulator to return via one of two possible
+points of return it passes to the emulator.  The emulator, if
+successful in its emulation, jumps to ret_from_exception (passed in
+r9) and the kernel takes care of returning control from the trap to
+the user code.  If the emulator is unable to emulate the instruction,
+it returns via _fpundefinstr (passed via lr) and the kernel halts the
+user program with a core dump.
+
+On entry to the emulator r10 points to an area of private FP workspace
+reserved in the thread structure for this process.  This is where the
+emulator saves its registers across calls.  The first word of this area
+is used as a flag to detect the first time a process uses floating point,
+so that the emulator startup cost can be avoided for tasks that don't
+want it.
+
+This routine does three things:
+
+1) It saves SP into a variable called userRegisters.  The kernel has
+created a struct pt_regs on the stack and saved the user registers
+into it.  See /usr/include/asm/proc/ptrace.h for details.  The
+emulator code uses userRegisters as the base of an array of words from
+which the contents of the registers can be extracted.
+
+2) It calls EmulateAll to emulate a floating point instruction.
+EmulateAll returns 1 if the emulation was successful, or 0 if not.
+
+3) If an instruction has been emulated successfully, it looks ahead at
+the next instruction.  If it is a floating point instruction, it
+executes the instruction, without returning to user space.  In this
+way it repeatedly looks ahead and executes floating point instructions
+until it encounters a non floating point instruction, at which time it
+returns via _fpreturn.
+
+This is done to reduce the effect of the trap overhead on each
+floating point instructions.  GCC attempts to group floating point
+instructions to allow the emulator to spread the cost of the trap over
+several floating point instructions.  */
+
+       .globl  nwfpe_enter
+nwfpe_enter:
+       /* ?? Could put userRegisters and fpa11 into fixed regs during
+          emulation.  This would reduce load/store overhead at the expense
+          of stealing two regs from the register allocator.  Not sure if
+          it's worth it.  */
+       ldr r4, =userRegisters
+        str sp, [r4]                   @ save pointer to user regs
+       ldr r4, =fpa11
+       str r10, [r4]                   @ store pointer to our state
+        mov r4, sp                     @ use r4 for local pointer
+        mov r10, lr                    @ save the failure-return addresses
+
+        ldr r5, [r4, #60]              @ get contents of PC;
+       ldr r0, [r5, #-4]               @ get actual instruction into r0
+emulate:
+       bl EmulateAll                   @ emulate the instruction
+       cmp r0, #0                      @ was emulation successful
+        moveq pc, r10                  @ no, return failure
+
+next:
+__x1:  ldrt    r6, [r5], #4            @ get the next instruction and
+                                       @ increment PC
+
+       and   r2, r6, #0x0F000000       @ test for FP insns
+        teq   r2, #0x0C000000
+        teqne r2, #0x0D000000
+        teqne r2, #0x0E000000
+        movne pc, r9                   @ return ok if not a fp insn
+
+        str r5, [r4, #60]              @ update PC copy in regs
+
+        mov r0, r6                     @ save a copy
+        ldr r1, [r4, #64]              @ fetch the condition codes
+       bl  checkCondition              @ check the condition
+       cmp r0, #0                      @ r0 = 0 ==> condition failed
+
+        @ if condition code failed to match, next insn
+       beq next                        @ get the next instruction;
+           
+        mov r0, r6                     @ prepare for EmulateAll()
+       b emulate                       @ if r0 != 0, goto EmulateAll
+
+       @ We need to be prepared for the instruction at __x1 to fault.
+       @ Emit the appropriate exception gunk to fix things up.
+       .section .fixup,"ax"
+       .align
+__f1:  mov     pc, r9
+       .previous
+       .section __ex_table,"a"
+       .align 3
+       .long   __x1, __f1
+       .previous
diff --git a/arch/arm/nwfpe/entry26.S b/arch/arm/nwfpe/entry26.S
new file mode 100644 (file)
index 0000000..6b1ec33
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    (c) Philip Blundell 1998-1999
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "../lib/constants.h"
+
+/* This is the kernel's entry point into the floating point emulator.
+It is called from the kernel with code similar to this:
+
+       mov     fp, #0
+       teqp    pc, #I_BIT | MODE_SVC
+       ldr     r4, .LC2
+       ldr     pc, [r4]                @ Call FP module USR entry point
+
+The kernel expects the emulator to return via one of two possible
+points of return it passes to the emulator.  The emulator, if
+successful in its emulation, jumps to ret_from_exception and the
+kernel takes care of returning control from the trap to the user code.
+If the emulator is unable to emulate the instruction, it returns to
+fpundefinstr and the kernel halts the user program with a core dump.
+
+This routine does four things:
+
+1) It saves SP into a variable called userRegisters.  The kernel has
+created a struct pt_regs on the stack and saved the user registers
+into it.  See /usr/include/asm/proc/ptrace.h for details.  The
+emulator code uses userRegisters as the base of an array of words from
+which the contents of the registers can be extracted.
+
+2) It locates the FP emulator work area within the TSS structure and
+points `fpa11' to it.
+
+3) It calls EmulateAll to emulate a floating point instruction.
+EmulateAll returns 1 if the emulation was successful, or 0 if not.
+
+4) If an instruction has been emulated successfully, it looks ahead at
+the next instruction.  If it is a floating point instruction, it
+executes the instruction, without returning to user space.  In this
+way it repeatedly looks ahead and executes floating point instructions
+until it encounters a non floating point instruction, at which time it
+returns via _fpreturn.
+
+This is done to reduce the effect of the trap overhead on each
+floating point instructions.  GCC attempts to group floating point
+instructions to allow the emulator to spread the cost of the trap over
+several floating point instructions.  */
+
+       .globl  nwfpe_enter
+nwfpe_enter:
+       ldr     r4, =userRegisters
+       str     sp, [r4]                @ save pointer to user regs
+
+       mov     r10, sp, lsr #13        @ find workspace
+       mov     r10, r10, lsl #13
+       add     r10, r10, #TSS_FPESAVE
+
+       ldr     r4, =fpa11
+       str     r10, [r4]               @ store pointer to our state
+       mov     r4, sp                  @ use r4 for local pointer
+
+       ldr     r5, [r4, #60]           @ get contents of PC
+       bic     r5, r5, #0xfc000003
+       ldr     r0, [r5, #-4]           @ get actual instruction into r0
+       bl      EmulateAll              @ emulate the instruction
+1:     cmp     r0, #0                  @ was emulation successful
+       beq     fpundefinstr            @ no, return failure
+
+next:
+       ldrt    r6, [r5], #4            @ get the next instruction and
+                                       @ increment PC
+
+       and     r2, r6, #0x0F000000     @ test for FP insns
+       teq     r2, #0x0C000000
+       teqne   r2, #0x0D000000
+       teqne   r2, #0x0E000000
+       bne     ret_from_exception      @ return ok if not a fp insn
+
+       ldr     r9, [r4, #60]           @ get new condition codes
+       and     r9, r9, #0xfc000003
+       orr     r7, r5, r9
+       str     r7, [r4, #60]           @ update PC copy in regs
+
+       mov     r0, r6                  @ save a copy
+       mov     r1, r9                  @ fetch the condition codes
+       bl      checkCondition          @ check the condition
+       cmp     r0, #0                  @ r0 = 0 ==> condition failed
+
+       @ if condition code failed to match, next insn
+       beq     next                    @ get the next instruction;
+           
+       mov     r0, r6                  @ prepare for EmulateAll()
+       adr     lr, 1b
+       orr     lr, lr, #3
+       b       EmulateAll              @ if r0 != 0, goto EmulateAll
diff --git a/arch/arm/nwfpe/extended_cpdo.c b/arch/arm/nwfpe/extended_cpdo.c
new file mode 100644 (file)
index 0000000..1c5c661
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+floatx80 getExtendedConstant(unsigned int);
+
+floatx80 floatx80_exp(floatx80 Fm);
+floatx80 floatx80_ln(floatx80 Fm);
+floatx80 floatx80_sin(floatx80 rFm);
+floatx80 floatx80_cos(floatx80 rFm);
+floatx80 floatx80_arcsin(floatx80 rFm);
+floatx80 floatx80_arctan(floatx80 rFm);
+floatx80 floatx80_log(floatx80 rFm);
+floatx80 floatx80_tan(floatx80 rFm);
+floatx80 floatx80_arccos(floatx80 rFm);
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm);
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm);
+
+unsigned int ExtendedCPDO(const unsigned int opcode)
+{
+   floatx80 rFm, rFn;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   //fp_printk("ExtendedCPDO(0x%08x)\n",opcode);
+   
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getExtendedConstant(Fm);
+   }
+   else
+   {  
+     switch (fpa11->fpreg[Fm].fType)
+     {
+        case typeSingle:
+          rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+        break;
+
+        case typeDouble:
+          rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+        break;
+        
+        case typeExtended:
+          rFm = fpa11->fpreg[Fm].fValue.fExtended;
+        break;
+        
+        default: return 0;
+     }
+   }
+   
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fpreg[Fn].fType)
+      {
+        case typeSingle:
+          rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+        break;
+
+        case typeDouble:
+          rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+        break;
+        
+        case typeExtended:
+          rFn = fpa11->fpreg[Fn].fValue.fExtended;
+        break;
+        
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm);
+      break;
+
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+      break;
+
+      case MNF_CODE:
+         rFm.high ^= 0x8000;
+         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+      break;
+
+      case ABS_CODE:
+         rFm.high &= 0x7fff;
+         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = 
+             int32_to_floatx80(floatx80_to_int32(rFm));
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+      
+      default:
+      {
+        nRc = 0;
+      }
+   }
+   
+   if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended;
+   return nRc;
+}
+
+#if 0
+floatx80 floatx80_exp(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_ln(floatx80 Fm)
+{
+//series
+}
+
+floatx80 floatx80_sin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_cos(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arcsin(floatx80 rFm)
+{
+//series
+}
+
+floatx80 floatx80_arctan(floatx80 rFm)
+{
+  //series
+}
+
+floatx80 floatx80_log(floatx80 rFm)
+{
+  return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7));
+}
+
+floatx80 floatx80_tan(floatx80 rFm)
+{
+  return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm));
+}
+
+floatx80 floatx80_arccos(floatx80 rFm)
+{
+   //return floatx80_sub(halfPi,floatx80_arcsin(rFm));
+}
+
+floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm)
+{
+  return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); 
+}
+
+floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm)
+{
+  return floatx80_arctan(floatx80_div(rFn,rFm)); 
+}
+#endif
diff --git a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c
new file mode 100644 (file)
index 0000000..506821c
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "fpa11.h"
+#include "milieu.h"
+#include "fpopcode.h"
+
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+/* forward declarations */
+unsigned int EmulateCPDO(const unsigned int);
+unsigned int EmulateCPDT(const unsigned int);
+unsigned int EmulateCPRT(const unsigned int);
+
+/* Emulator registers */
+FPA11 *fpa11;
+
+/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
+void resetFPA11(void)
+{
+  int i;
+  /* initialize the registers */
+  for (i=0;i<=7;i++)
+  {
+    fpa11->fpreg[i].fType = typeNone;
+  }
+  
+  /* FPSR: set system id to FP_EMULATOR, clear all other bits */
+  fpa11->fpsr = FP_EMULATOR;
+  
+  /* FPCR: set SB, AB and DA bits, clear all others */
+#if MAINTAIN_FPCR         
+  fpa11->fpcr = MASK_RESET;
+#endif
+}
+
+void SetRoundingMode(const unsigned int opcode)
+{
+#if MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_MODE;
+#endif   
+   switch (opcode & MASK_ROUNDING_MODE)
+   {
+      default:
+      case ROUND_TO_NEAREST:
+         float_rounding_mode = float_round_nearest_even;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_TO_NEAREST;
+#endif         
+      break;
+      
+      case ROUND_TO_PLUS_INFINITY:
+         float_rounding_mode = float_round_up;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
+#endif         
+      break;
+      
+      case ROUND_TO_MINUS_INFINITY:
+         float_rounding_mode = float_round_down;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
+#endif         
+      break;
+      
+      case ROUND_TO_ZERO:
+         float_rounding_mode = float_round_to_zero;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_TO_ZERO;
+#endif         
+      break;
+  }
+}
+
+void SetRoundingPrecision(const unsigned int opcode)
+{
+#if MAINTAIN_FPCR
+   fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
+#endif   
+   switch (opcode & MASK_ROUNDING_PRECISION)
+   {
+      case ROUND_SINGLE:
+         floatx80_rounding_precision = 32;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_SINGLE;
+#endif         
+      break;
+      
+      case ROUND_DOUBLE:
+         floatx80_rounding_precision = 64;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_DOUBLE;
+#endif         
+      break;
+      
+      case ROUND_EXTENDED:
+         floatx80_rounding_precision = 80;
+#if MAINTAIN_FPCR         
+         fpa11->fpcr |= ROUND_EXTENDED;
+#endif         
+      break;
+      
+      default: floatx80_rounding_precision = 80;
+  }
+}
+
+/* Emulate the instruction in the opcode. */
+unsigned int EmulateAll(unsigned int opcode)
+{
+  unsigned int nRc = 0;
+
+  if (fpa11->initflag == 0)            /* good place for __builtin_expect */
+  {
+    resetFPA11();
+    SetRoundingMode(ROUND_TO_NEAREST);
+    SetRoundingPrecision(ROUND_EXTENDED);
+    fpa11->initflag = 1;
+  }
+
+  if (TEST_OPCODE(opcode,MASK_CPRT))
+  {
+    /* Emulate conversion opcodes. */
+    /* Emulate register transfer opcodes. */
+    /* Emulate comparison opcodes. */
+    nRc = EmulateCPRT(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDO))
+  {
+    /* Emulate monadic arithmetic opcodes. */
+    /* Emulate dyadic arithmetic opcodes. */
+    nRc = EmulateCPDO(opcode);
+  }
+  else if (TEST_OPCODE(opcode,MASK_CPDT))
+  {
+    /* Emulate load/store opcodes. */
+    /* Emulate load/store multiple opcodes. */
+    nRc = EmulateCPDT(opcode);
+  }
+  else
+  {
+    /* Invalid instruction detected.  Return FALSE. */
+    nRc = 0;
+  }
+
+  return(nRc);
+}
+
+#if 0
+unsigned int EmulateAll1(unsigned int opcode)
+{
+  switch ((opcode >> 24) & 0xf)
+  {
+     case 0xc:
+     case 0xd:
+       if ((opcode >> 20) & 0x1)
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformLDF(opcode); break;
+             case 0x2: return PerformLFM(opcode); break;
+             default: return 0;
+          }
+       }
+       else
+       {
+          switch ((opcode >> 8) & 0xf)
+          {
+             case 0x1: return PerformSTF(opcode); break;
+             case 0x2: return PerformSFM(opcode); break;
+             default: return 0;
+          }
+      }
+     break;
+     
+     case 0xe: 
+       if (opcode & 0x10)
+         return EmulateCPDO(opcode);
+       else
+         return EmulateCPRT(opcode);
+     break;
+  
+     default: return 0;
+  }
+}
+#endif
+
diff --git a/arch/arm/nwfpe/fpa11.h b/arch/arm/nwfpe/fpa11.h
new file mode 100644 (file)
index 0000000..4a47a29
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPA11_H__
+#define __FPA11_H__
+
+/* includes */
+#include "fpsr.h"              /* FP control and status register definitions */
+#include "softfloat.h"
+
+#define                typeNone                0x00
+#define                typeSingle              0x01
+#define                typeDouble              0x02
+#define                typeExtended            0x03
+
+typedef struct tagFPREG {
+   unsigned int fType;
+   union {
+      float32  fSingle;
+      float64  fDouble;
+      floatx80 fExtended;
+   } fValue;
+} FPREG;
+
+/* FPA11 device model */
+typedef struct tagFPA11 {
+  int initflag;                        /* this is special.  The kernel guarantees
+                                  to set it to 0 when a thread is launched,
+                                  so we can use it to detect whether this
+                                  instance of the emulator needs to be
+                                  initialised. */
+  FPREG fpreg[8];              /* 8 floating point registers */
+  FPSR fpsr;                   /* floating point status register */
+  FPCR fpcr;                   /* floating point control register */
+} FPA11;
+
+extern void resetFPA11(void);
+extern void SetRoundingMode(const unsigned int);
+extern void SetRoundingPrecision(const unsigned int);
+
+extern FPA11 *fpa11;
+
+#endif
diff --git a/arch/arm/nwfpe/fpa11.inl b/arch/arm/nwfpe/fpa11.inl
new file mode 100644 (file)
index 0000000..321ab7c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "fpa11.h"
+
+/* Read and write floating point status register */
+extern __inline__ unsigned int readFPSR(void)
+{
+  return(fpa11->fpsr);
+}
+
+extern __inline__ void writeFPSR(FPSR reg)
+{
+  /* the sysid byte in the status register is readonly */
+  fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID);
+}
+
+/* Read and write floating point control register */
+extern __inline__ FPCR readFPCR(void)
+{
+  /* clear SB, AB and DA bits before returning FPCR */
+  return(fpa11->fpcr & ~MASK_RFC);
+}
+
+extern __inline__ void writeFPCR(FPCR reg)
+{
+  fpa11->fpcr &= ~MASK_WFC;            /* clear SB, AB and DA bits */
+  fpa11->fpcr |= (reg & MASK_WFC);     /* write SB, AB and DA bits */
+}
diff --git a/arch/arm/nwfpe/fpa11_cpdo.c b/arch/arm/nwfpe/fpa11_cpdo.c
new file mode 100644 (file)
index 0000000..c337c55
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "fpa11.h"
+#include "fpopcode.h"
+
+unsigned int SingleCPDO(const unsigned int opcode);
+unsigned int DoubleCPDO(const unsigned int opcode);
+unsigned int ExtendedCPDO(const unsigned int opcode);
+
+unsigned int EmulateCPDO(const unsigned int opcode)
+{
+   unsigned int Fd, nType, nDest, nRc = 1;
+   
+   //fp_printk("EmulateCPDO(0x%08x)\n",opcode);
+
+   /* Get the destination size.  If not valid let Linux perform
+      an invalid instruction trap. */
+   nDest = getDestinationSize(opcode);
+   if (typeNone == nDest) return 0;
+   
+   SetRoundingMode(opcode);
+     
+   /* Compare the size of the operands in Fn and Fm.
+      Choose the largest size and perform operations in that size,
+      in order to make use of all the precision of the operands. 
+      If Fm is a constant, we just grab a constant of a size 
+      matching the size of the operand in Fn. */
+   if (MONADIC_INSTRUCTION(opcode))
+     nType = nDest;
+   else
+     nType = fpa11->fpreg[getFn(opcode)].fType;
+   
+   if (!CONSTANT_FM(opcode))
+   {
+     register unsigned int Fm = getFm(opcode);
+     if (nType < fpa11->fpreg[Fm].fType)
+     {
+        nType = fpa11->fpreg[Fm].fType;
+     }
+   }
+
+   switch (nType)
+   {
+      case typeSingle   : nRc = SingleCPDO(opcode);   break;
+      case typeDouble   : nRc = DoubleCPDO(opcode);   break;
+      case typeExtended : nRc = ExtendedCPDO(opcode); break;
+      default           : nRc = 0;
+   }
+
+   /* If the operation succeeded, check to see if the result in the
+      destination register is the correct size.  If not force it
+      to be. */
+   Fd = getFd(opcode);
+   nType = fpa11->fpreg[Fd].fType;
+   if ((0 != nRc) && (nDest != nType))
+   {
+     switch (nDest)
+     {
+       case typeSingle:
+       {
+         if (typeDouble == nType)
+           fpa11->fpreg[Fd].fValue.fSingle = 
+              float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble);
+         else
+           fpa11->fpreg[Fd].fValue.fSingle = 
+              floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended);
+       }
+       break;
+          
+       case typeDouble:
+       {
+         if (typeSingle == nType)
+           fpa11->fpreg[Fd].fValue.fDouble = 
+              float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle);
+         else
+           fpa11->fpreg[Fd].fValue.fDouble = 
+              floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended);
+       }
+       break;
+          
+       case typeExtended:
+       {
+         if (typeSingle == nType)
+           fpa11->fpreg[Fd].fValue.fExtended = 
+              float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle);
+         else
+           fpa11->fpreg[Fd].fValue.fExtended = 
+              float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble);
+       }
+       break;
+     }
+     
+     fpa11->fpreg[Fd].fType = nDest;
+   }
+   
+   return nRc;
+}
diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c
new file mode 100644 (file)
index 0000000..9617a79
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    (c) Philip Blundell, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+#include <asm/uaccess.h>
+
+extern __inline__
+void loadSingle(const unsigned int Fn,const unsigned int *pMem)
+{
+   fpa11->fpreg[Fn].fType = typeSingle;
+   get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem);
+}
+
+extern __inline__
+void loadDouble(const unsigned int Fn,const unsigned int *pMem)
+{
+   unsigned int *p;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble;
+   fpa11->fpreg[Fn].fType = typeDouble;
+   get_user(p[0], &pMem[1]);
+   get_user(p[1], &pMem[0]); /* sign & exponent */
+}   
+
+extern __inline__
+void loadExtended(const unsigned int Fn,const unsigned int *pMem)
+{
+   unsigned int *p;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended;
+   fpa11->fpreg[Fn].fType = typeExtended;
+   get_user(p[0], &pMem[0]);  /* sign & exponent */
+   get_user(p[1], &pMem[2]);  /* ls bits */
+   get_user(p[2], &pMem[1]);  /* ms bits */
+}   
+
+extern __inline__
+void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
+{
+   register unsigned int *p;
+   unsigned long x;
+
+   p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
+   get_user(x, &pMem[0]);
+   fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003;
+   
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeSingle:
+      case typeDouble:
+      {
+         get_user(p[0], &pMem[2]);  /* Single */
+         get_user(p[1], &pMem[1]);  /* double msw */
+         p[2] = 0;        /* empty */
+      }
+      break; 
+   
+      case typeExtended:
+      {
+         get_user(p[1], &pMem[2]);
+         get_user(p[2], &pMem[1]);  /* msw */
+         p[0] = (x & 0x80003fff);      
+      }
+      break;
+   }
+}
+
+extern __inline__
+void storeSingle(const unsigned int Fn,unsigned int *pMem)
+{
+   float32 val;
+   register unsigned int *p = (unsigned int*)&val;
+   
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeDouble: 
+         val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble);
+      break;
+
+      case typeExtended: 
+         val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fValue.fSingle;
+   }
+  
+   put_user(p[0], pMem);
+}   
+
+extern __inline__
+void storeDouble(const unsigned int Fn,unsigned int *pMem)
+{
+   float64 val;
+   register unsigned int *p = (unsigned int*)&val;
+
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeSingle: 
+         val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+      break;
+
+      case typeExtended:
+         val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fValue.fDouble;
+   }
+   put_user(p[1], &pMem[0]);   /* msw */
+   put_user(p[0], &pMem[1]);   /* lsw */
+}   
+
+extern __inline__
+void storeExtended(const unsigned int Fn,unsigned int *pMem)
+{
+   floatx80 val;
+   register unsigned int *p = (unsigned int*)&val;
+   
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeSingle: 
+         val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+      break;
+
+      case typeDouble: 
+         val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+      break;
+
+      default: val = fpa11->fpreg[Fn].fValue.fExtended;
+   }
+   
+   put_user(p[0], &pMem[0]); /* sign & exp */
+   put_user(p[1], &pMem[2]);
+   put_user(p[2], &pMem[1]); /* msw */
+}   
+
+extern __inline__
+void storeMultiple(const unsigned int Fn,unsigned int *pMem)
+{
+   register unsigned int nType, *p;
+   
+   p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
+   nType = fpa11->fpreg[Fn].fType;
+   
+   switch (nType)
+   {
+      case typeSingle:
+      case typeDouble:
+      {
+        put_user(p[0], &pMem[2]); /* single */
+        put_user(p[1], &pMem[1]); /* double msw */
+        put_user(nType << 14, &pMem[0]);
+      }
+      break; 
+   
+      case typeExtended:
+      {
+        put_user(p[2], &pMem[1]); /* msw */
+        put_user(p[1], &pMem[2]);
+        put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
+      }
+      break;
+   }
+}
+
+unsigned int PerformLDF(const unsigned int opcode)
+{
+   unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
+   
+   //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+
+   pBase = (unsigned int*)readRegister(getRn(opcode));
+   if (REG_PC == getRn(opcode)) pBase += 2;
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode);
+   else
+     pFinal -= getOffset(opcode);
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   switch (opcode & MASK_TRANSFER_LENGTH)
+   {
+      case TRANSFER_SINGLE  : loadSingle(getFd(opcode),pAddress);   break;
+      case TRANSFER_DOUBLE  : loadDouble(getFd(opcode),pAddress);   break;
+      case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
+      default: nRc = 0;
+   }
+   
+   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return nRc;
+}
+
+unsigned int PerformSTF(const unsigned int opcode)
+{
+   unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
+   
+   //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
+   SetRoundingMode(ROUND_TO_NEAREST);
+   
+   pBase = (unsigned int*)readRegister(getRn(opcode));
+   if (REG_PC == getRn(opcode)) pBase += 2;
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode);
+   else
+     pFinal -= getOffset(opcode);
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   switch (opcode & MASK_TRANSFER_LENGTH)
+   {
+      case TRANSFER_SINGLE  : storeSingle(getFd(opcode),pAddress);   break;
+      case TRANSFER_DOUBLE  : storeDouble(getFd(opcode),pAddress);   break;
+      case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
+      default: nRc = 0;
+   }
+   
+   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return nRc;
+}
+
+unsigned int PerformLFM(const unsigned int opcode)
+{
+   unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+   pBase = (unsigned int*)readRegister(getRn(opcode));
+   if (REG_PC == getRn(opcode)) pBase += 2;
+
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode);
+   else
+     pFinal -= getOffset(opcode);
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   Fd = getFd(opcode);
+   for (i=getRegisterCount(opcode);i>0;i--)
+   {
+     loadMultiple(Fd,pAddress);
+     pAddress += 3; Fd++;
+     if (Fd == 8) Fd = 0;
+   }
+
+   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return 1;
+}
+
+unsigned int PerformSFM(const unsigned int opcode)
+{
+   unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+   
+   pBase = (unsigned int*)readRegister(getRn(opcode));
+   if (REG_PC == getRn(opcode)) pBase += 2;
+   
+   pFinal = pBase;
+   if (BIT_UP_SET(opcode))
+     pFinal += getOffset(opcode);
+   else
+     pFinal -= getOffset(opcode);
+
+   if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
+
+   Fd = getFd(opcode);
+   for (i=getRegisterCount(opcode);i>0;i--)
+   {
+     storeMultiple(Fd,pAddress);
+     pAddress += 3; Fd++;
+     if (Fd == 8) Fd = 0;
+   }
+
+   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   return 1;
+}
+
+#if 1
+unsigned int EmulateCPDT(const unsigned int opcode)
+{
+  unsigned int nRc = 0;
+
+  //fp_printk("EmulateCPDT(0x%08x)\n",opcode);
+  
+  if (LDF_OP(opcode))
+  {
+    nRc = PerformLDF(opcode);
+  }
+  else if (LFM_OP(opcode))
+  {
+    nRc = PerformLFM(opcode);
+  }
+  else if (STF_OP(opcode))
+  {
+    nRc = PerformSTF(opcode);
+  } 
+  else if (SFM_OP(opcode))
+  {
+    nRc = PerformSFM(opcode);
+  }
+  else
+  {
+    nRc = 0;
+  }
+  
+  return nRc;
+}
+#endif
diff --git a/arch/arm/nwfpe/fpa11_cprt.c b/arch/arm/nwfpe/fpa11_cprt.c
new file mode 100644 (file)
index 0000000..bfe13ba
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    (c) Philip Blundell, 1999
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "milieu.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+#include "fpa11.inl"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+extern flag floatx80_is_nan(floatx80);
+extern flag float64_is_nan( float64);
+extern flag float32_is_nan( float32);
+
+void SetRoundingMode(const unsigned int opcode);
+
+unsigned int PerformFLT(const unsigned int opcode);
+unsigned int PerformFIX(const unsigned int opcode);
+
+static unsigned int
+PerformComparison(const unsigned int opcode);
+
+unsigned int EmulateCPRT(const unsigned int opcode)
+{
+  unsigned int nRc = 1;
+
+  //fp_printk("EmulateCPRT(0x%08x)\n",opcode);
+
+  if (opcode & 0x800000)
+  {
+     /* This is some variant of a comparison (PerformComparison will
+       sort out which one).  Since most of the other CPRT
+       instructions are oddball cases of some sort or other it makes
+       sense to pull this out into a fast path.  */
+     return PerformComparison(opcode);
+  }
+
+  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
+  switch ((opcode & 0x700000) >> 20)
+  {
+    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
+    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
+    
+    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
+    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
+
+#if 0
+    /* ?? Not at all sure about the mode checks here.  Linux never
+       calls the emulator from a non-USR fault but we always run in SVC
+       mode.  Is there even any point trying to emulate the way FPA11
+       behaves in this respect?
+
+       No - and I quote: 'The FPCR may only be present in some
+       implementations: it is there to control the hardware in an
+       implementation-specific manner, ...  The user mode of the
+       ARM is not permitted to use this register, and the WFC and
+       RFC instructions will trap if tried from user mode.'
+       Therefore, we do not provide the RFC and WFC instructions.
+        (rmk, 3/05/1999)
+     */
+    case  WFC_CODE >> 20:
+    {
+       int mode = 0;
+       __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
+       nRc = (0x13 == mode) ? 1 : 0;   /* in SVC processor mode? */
+       if (nRc) writeFPCR(readRegister(getRd(opcode)));
+    }
+    break;
+    
+    case  RFC_CODE >> 20:
+    {
+       int mode = 0;
+       __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
+       nRc = (0x13 == mode) ? 1 : 0;   /* in SVC processor mode? */
+       if (nRc) writeRegister(getRd(opcode),readFPCR()); break;
+    }
+    break;
+#endif
+
+    default: nRc = 0;
+  }
+  
+  return nRc;
+}
+
+unsigned int PerformFLT(const unsigned int opcode)
+{
+   unsigned int nRc = 1;
+   SetRoundingMode(opcode);
+   SetRoundingPrecision(opcode);
+   
+   switch (opcode & MASK_ROUNDING_PRECISION)
+   {
+      case ROUND_SINGLE:
+      {
+        fpa11->fpreg[getFn(opcode)].fType = typeSingle;
+        fpa11->fpreg[getFn(opcode)].fValue.fSingle =
+          int32_to_float32(readRegister(getRd(opcode)));
+      }
+      break;
+
+      case ROUND_DOUBLE:
+      {
+        fpa11->fpreg[getFn(opcode)].fType = typeDouble;
+        fpa11->fpreg[getFn(opcode)].fValue.fDouble =
+            int32_to_float64(readRegister(getRd(opcode)));
+      }
+      break;
+        
+      case ROUND_EXTENDED:
+      {
+        fpa11->fpreg[getFn(opcode)].fType = typeExtended;
+        fpa11->fpreg[getFn(opcode)].fValue.fExtended =
+          int32_to_floatx80(readRegister(getRd(opcode)));
+      }
+      break;
+      
+      default: nRc = 0;
+  }
+  
+  return nRc;
+}
+
+unsigned int PerformFIX(const unsigned int opcode)
+{
+   unsigned int nRc = 1;
+   unsigned int Fn = getFm(opcode);
+   
+   SetRoundingMode(opcode);
+
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeSingle:
+      {
+         writeRegister(getRd(opcode),
+                      float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle));
+      }
+      break;
+
+      case typeDouble:
+      {
+         writeRegister(getRd(opcode),
+                      float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble));
+      }
+      break;
+                      
+      case typeExtended:
+      {
+         writeRegister(getRd(opcode),
+                      floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended));
+      }
+      break;
+      
+      default: nRc = 0;
+  }
+  
+  return nRc;
+}
+
+   
+static unsigned int __inline__
+PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
+{
+   unsigned int flags = 0;
+
+   /* test for less than condition */
+   if (floatx80_lt(Fn,Fm))
+   {
+      flags |= CC_NEGATIVE;
+   }
+  
+   /* test for equal condition */
+   if (floatx80_eq(Fn,Fm))
+   {
+      flags |= CC_ZERO;
+   }
+
+   /* test for greater than or equal condition */
+   if (floatx80_lt(Fm,Fn))
+   {
+      flags |= CC_CARRY;
+   }
+   
+   writeConditionCodes(flags);
+   return 1;
+}
+
+/* This instruction sets the flags N, Z, C, V in the FPSR. */
+   
+static unsigned int PerformComparison(const unsigned int opcode)
+{
+   unsigned int Fn, Fm;
+   floatx80 rFn, rFm;
+   int e_flag = opcode & 0x400000;     /* 1 if CxFE */
+   int n_flag = opcode & 0x200000;     /* 1 if CNxx */
+   unsigned int flags = 0;
+
+   //fp_printk("PerformComparison(0x%08x)\n",opcode);
+
+   Fn = getFn(opcode);
+   Fm = getFm(opcode);
+
+   /* Check for unordered condition and convert all operands to 80-bit
+      format.
+      ?? Might be some mileage in avoiding this conversion if possible.
+      Eg, if both operands are 32-bit, detect this and do a 32-bit
+      comparison (cheaper than an 80-bit one).  */
+   switch (fpa11->fpreg[Fn].fType)
+   {
+      case typeSingle: 
+        //fp_printk("single.\n");
+       if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle))
+          goto unordered;
+        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+      break;
+
+      case typeDouble: 
+        //fp_printk("double.\n");
+       if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble))
+          goto unordered;
+        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+      break;
+      
+      case typeExtended: 
+        //fp_printk("extended.\n");
+       if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended))
+          goto unordered;
+        rFn = fpa11->fpreg[Fn].fValue.fExtended;
+      break;
+      
+      default: return 0;
+   }
+
+   if (CONSTANT_FM(opcode))
+   {
+     //fp_printk("Fm is a constant: #%d.\n",Fm);
+     rFm = getExtendedConstant(Fm);
+     if (floatx80_is_nan(rFm))
+        goto unordered;
+   }
+   else
+   {
+     //fp_printk("Fm = r%d which contains a ",Fm);
+      switch (fpa11->fpreg[Fm].fType)
+      {
+         case typeSingle: 
+           //fp_printk("single.\n");
+          if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle))
+             goto unordered;
+           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+         break;
+
+         case typeDouble: 
+           //fp_printk("double.\n");
+          if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble))
+             goto unordered;
+           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+         break;
+      
+         case typeExtended: 
+           //fp_printk("extended.\n");
+          if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended))
+             goto unordered;
+           rFm = fpa11->fpreg[Fm].fValue.fExtended;
+         break;
+      
+         default: return 0;
+      }
+   }
+
+   if (n_flag)
+   {
+      rFm.high ^= 0x8000;
+   }
+
+   return PerformComparisonOperation(rFn,rFm);
+
+ unordered:
+   /* ?? The FPA data sheet is pretty vague about this, in particular
+      about whether the non-E comparisons can ever raise exceptions.
+      This implementation is based on a combination of what it says in
+      the data sheet, observation of how the Acorn emulator actually
+      behaves (and how programs expect it to) and guesswork.  */
+   flags |= CC_OVERFLOW;
+
+   if (BIT_AC & readFPSR()) flags |= CC_CARRY;
+
+   if (e_flag) float_raise(float_flag_invalid);
+
+   writeConditionCodes(flags);
+   return 1;
+}
diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
new file mode 100644 (file)
index 0000000..fb05fc6
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+    (c) Philip Blundell, 1998-1999
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+/* XXX */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/pgtable.h>
+/* XXX */
+
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpmodule.h"
+#include "fpa11.h"
+#include "fpa11.inl"
+
+/* external data */
+extern FPA11 *fpa11;
+
+/* kernel symbols required for signal handling */
+typedef struct task_struct*    PTASK;
+
+#ifdef MODULE
+int fp_printk(const char *,...);
+void fp_send_sig(unsigned long sig, PTASK p, int priv);
+#if LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Scott Bambrough <scottb@corelcomputer.com>");
+MODULE_DESCRIPTION("NWFPE floating point emulator");
+#endif
+
+#else
+#define fp_printk      printk
+#define fp_send_sig    send_sig
+#define kern_fp_enter  fp_enter
+#endif
+
+/* kernel function prototypes required */
+void C_SYMBOL_NAME(fp_setup)(void);
+
+/* external declarations for saved kernel symbols */
+extern unsigned int C_SYMBOL_NAME(kern_fp_enter);
+
+/* forward declarations */
+extern void nwfpe_enter(void);
+
+/* Original value of fp_enter from kernel before patched by fpe_init. */ 
+static unsigned int orig_fp_enter;
+
+/* Address of user registers on the kernel stack. */
+unsigned int *userRegisters;
+
+void __init C_SYMBOL_NAME(fpe_version)(void)
+{
+  static const char szTitle[] = "<4>NetWinder Floating Point Emulator ";
+  static const char szVersion[] = "V0.94.1 ";
+  static const char szCopyright[] = "(c) 1998 Corel Computer Corp.\n";
+  C_SYMBOL_NAME(fp_printk)(szTitle);
+  C_SYMBOL_NAME(fp_printk)(szVersion);
+  C_SYMBOL_NAME(fp_printk)(szCopyright);
+}
+
+int __init fpe_init(void)
+{
+  /* Display title, version and copyright information. */
+  C_SYMBOL_NAME(fpe_version)();
+
+  /* Save pointer to the old FP handler and then patch ourselves in */
+  orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter);
+  C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter);
+
+  return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+  return(fpe_init());
+}
+
+void cleanup_module(void)
+{
+  /* Restore the values we saved earlier. */
+  C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter;
+}
+#endif
+
+#define _ARM_pc 60
+#define _ARM_cpsr 64
+
+/*
+ScottB:  November 4, 1998
+
+Moved this function out of softfloat-specialize into fpmodule.c.
+This effectively isolates all the changes required for integrating with the
+Linux kernel into fpmodule.c.  Porting to NetBSD should only require modifying
+fpmodule.c to integrate with the NetBSD kernel (I hope!).
+
+[1/1/99: Not quite true any more unfortunately.  There is Linux-specific
+code to access data in user space in some other source files at the 
+moment.  --philb]
+
+float_exception_flags is a global variable in SoftFloat.
+
+This function is called by the SoftFloat routines to raise a floating
+point exception.  We check the trap enable byte in the FPSR, and raise
+a SIGFPE exception if necessary.  If not the relevant bits in the 
+cumulative exceptions flag byte are set and we return.
+*/
+
+void float_raise(signed char flags)
+{
+#if 0
+  printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags,
+        __builtin_return_address(0), userRegisters[15]);
+#endif
+
+  float_exception_flags |= flags;
+  if (readFPSR() & (flags << 16))
+  {
+    /* raise exception */
+    C_SYMBOL_NAME(fp_send_sig)(SIGFPE,C_SYMBOL_NAME(current),1);
+  }
+  else
+  {
+    /* set the cumulative exceptions flags */
+    writeFPSR(flags);
+  }
+}
diff --git a/arch/arm/nwfpe/fpmodule.h b/arch/arm/nwfpe/fpmodule.h
new file mode 100644 (file)
index 0000000..39c7629
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPMODULE_H__
+#define __FPMODULE_H__
+
+#include <linux/config.h>
+
+#ifdef CONFIG_CPU_32
+#define REG_ORIG_R0    17
+#define REG_CPSR       16
+#else
+#define REG_ORIG_R0    16
+#define REG_CPSR       15
+#endif
+
+#define REG_PC         15
+#define REG_LR         14
+#define REG_SP         13
+#define REG_IP         12
+#define REG_FP         11
+#define REG_R10                10
+#define REG_R9         9
+#define REG_R9         9
+#define REG_R8         8
+#define REG_R7         7
+#define REG_R6         6
+#define REG_R5         5
+#define REG_R4         4
+#define REG_R3         3
+#define REG_R2         2
+#define REG_R1         1
+#define REG_R0         0
+
+#endif
diff --git a/arch/arm/nwfpe/fpmodule.inl b/arch/arm/nwfpe/fpmodule.inl
new file mode 100644 (file)
index 0000000..c76b7fd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+   NetWinder Floating Point Emulator
+   (c) Corel Computer Corporation, 1998
+
+   Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Address of user registers on the kernel stack. */
+extern unsigned int *userRegisters;
+
+extern __inline__
+unsigned int readRegister(const unsigned int nReg)
+{
+       /* Note: The CPU thinks it has dealt with the current instruction.  As
+          a result the program counter has been advanced to the next
+          instruction, and points 4 bytes beyond the actual instruction
+          that caused the invalid instruction trap to occur.  We adjust
+          for this in this routine.  LDF/STF instructions with Rn = PC
+          depend on the PC being correct, as they use PC+8 in their 
+          address calculations. */
+       unsigned int val = userRegisters[nReg];
+
+       if (REG_PC == nReg)
+               val -= 4;
+
+       return val;
+}
+
+extern __inline__
+void writeRegister(const unsigned int nReg, const unsigned int val)
+{
+       userRegisters[nReg] = val;
+}
+
+extern __inline__
+unsigned int readCPSR(void)
+{
+       return (readRegister(REG_CPSR));
+}
+
+extern __inline__
+void writeCPSR(const unsigned int val)
+{
+       writeRegister(REG_CPSR, val);
+}
+
+extern __inline__
+unsigned int readConditionCodes(void)
+{
+#ifdef __FPEM_TEST__
+       return (0);
+#else
+       return (readCPSR() & CC_MASK);
+#endif
+}
+
+extern __inline__
+void writeConditionCodes(const unsigned int val)
+{
+       unsigned int rval;
+
+       /*
+        * Operate directly on userRegisters since
+        * the CPSR may be the PC register itself.
+        */
+       rval = userRegisters[REG_CPSR] & ~CC_MASK;
+       userRegisters[REG_CPSR] = rval | (val & CC_MASK);
+}
+
+extern __inline__
+unsigned int readMemoryInt(unsigned int *pMem)
+{
+       return *pMem;
+}
diff --git a/arch/arm/nwfpe/fpopcode.c b/arch/arm/nwfpe/fpopcode.c
new file mode 100644 (file)
index 0000000..aa91e1e
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpsr.h"
+#include "fpa11.h"
+#include "fpmodule.h"
+#include "fpmodule.inl"
+
+static floatx80 floatx80Constant[] = {
+  { 0x0000, 0x0000000000000000ULL},    /* extended 0.0 */
+  { 0x3fff, 0x8000000000000000ULL},    /* extended 1.0 */
+  { 0x4000, 0x8000000000000000ULL},    /* extended 2.0 */
+  { 0x4000, 0xc000000000000000ULL},    /* extended 3.0 */
+  { 0x4001, 0x8000000000000000ULL},    /* extended 4.0 */
+  { 0x4001, 0xa000000000000000ULL},    /* extended 5.0 */
+  { 0x3ffe, 0x8000000000000000ULL},    /* extended 0.5 */
+  { 0x4002, 0xa000000000000000ULL}     /* extended 10.0 */
+};  
+
+static float64 float64Constant[] = {
+  0x0000000000000000ULL,               /* double 0.0 */
+  0x3ff0000000000000ULL,               /* double 1.0 */
+  0x4000000000000000ULL,               /* double 2.0 */
+  0x4008000000000000ULL,               /* double 3.0 */
+  0x4010000000000000ULL,               /* double 4.0 */
+  0x4014000000000000ULL,               /* double 5.0 */
+  0x3fe0000000000000ULL,               /* double 0.5 */
+  0x4024000000000000ULL                        /* double 10.0 */
+};  
+
+static float32 float32Constant[] = {
+  0x00000000,                          /* single 0.0 */
+  0x3f800000,                          /* single 1.0 */
+  0x40000000,                          /* single 2.0 */
+  0x40400000,                          /* single 3.0 */
+  0x40800000,                          /* single 4.0 */
+  0x40a00000,                          /* single 5.0 */
+  0x3f000000,                          /* single 0.5 */
+  0x41200000                           /* single 10.0 */
+};  
+
+floatx80 getExtendedConstant(const unsigned int nIndex)
+{
+   return floatx80Constant[nIndex];
+} 
+
+float64 getDoubleConstant(const unsigned int nIndex)
+{
+   return float64Constant[nIndex];
+} 
+
+float32 getSingleConstant(const unsigned int nIndex)
+{
+   return float32Constant[nIndex];
+} 
+
+unsigned int getTransferLength(const unsigned int opcode)
+{
+  unsigned int nRc;
+  
+  switch (opcode & MASK_TRANSFER_LENGTH)
+  {
+    case 0x00000000: nRc = 1; break; /* single precision */
+    case 0x00008000: nRc = 2; break; /* double precision */
+    case 0x00400000: nRc = 3; break; /* extended precision */
+    default: nRc = 0;
+  }
+  
+  return(nRc);
+}
+
+unsigned int getRegisterCount(const unsigned int opcode)
+{
+  unsigned int nRc;
+  
+  switch (opcode & MASK_REGISTER_COUNT)
+  {
+    case 0x00000000: nRc = 4; break;
+    case 0x00008000: nRc = 1; break;
+    case 0x00400000: nRc = 2; break;
+    case 0x00408000: nRc = 3; break;
+    default: nRc = 0;
+  }
+  
+  return(nRc);
+}
+
+unsigned int getRoundingPrecision(const unsigned int opcode)
+{
+  unsigned int nRc;
+  
+  switch (opcode & MASK_ROUNDING_PRECISION)
+  {
+    case 0x00000000: nRc = 1; break;
+    case 0x00000080: nRc = 2; break;
+    case 0x00080000: nRc = 3; break;
+    default: nRc = 0;
+  }
+  
+  return(nRc);
+}
+
+unsigned int getDestinationSize(const unsigned int opcode)
+{
+  unsigned int nRc;
+  
+  switch (opcode & MASK_DESTINATION_SIZE)
+  {
+    case 0x00000000: nRc = typeSingle; break;
+    case 0x00000080: nRc = typeDouble; break;
+    case 0x00080000: nRc = typeExtended; break;
+    default: nRc = typeNone;
+  }
+  
+  return(nRc);
+}
+
+/* contition code lookup table
+ index into the table is test code: EQ, NE, ... LT, GT, AL, NV
+ bit position in short is condition code: NZCV */
+unsigned short aCC[16] = {
+    0xF0F0, // EQ == Z set
+    0x0F0F, // NE
+    0xCCCC, // CS == C set
+    0x3333, // CC
+    0xFF00, // MI == N set
+    0x00FF, // PL
+    0xAAAA, // VS == V set
+    0x5555, // VC
+    0x0C0C, // HI == C set && Z clear
+    0xF3F3, // LS == C clear || Z set
+    0xAA55, // GE == (N==V)
+    0x55AA, // LT == (N!=V)
+    0x0A05, // GT == (!Z && (N==V))
+    0xF5FA, // LE == (Z || (N!=V))
+    0xFFFF, // AL always
+    0 // NV
+};
+
+unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes)
+{
+  return (aCC[opcode>>28] >> (ccodes>>28)) & 1;
+}
diff --git a/arch/arm/nwfpe/fpopcode.h b/arch/arm/nwfpe/fpopcode.h
new file mode 100644 (file)
index 0000000..d6d7aa1
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPOPCODE_H__
+#define __FPOPCODE_H__
+
+/*
+ARM Floating Point Instruction Classes
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+|c o n d|1 1 0 P|U|u|W|L|   Rn  |v|  Fd |0|0|0|1|  o f f s e t  | CPDT
+|c o n d|1 1 0 P|U|w|W|L|   Rn  |x|  Fd |0|0|0|1|  o f f s e t  | CPDT
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+|c o n d|1 1 1 0|a|b|c|d|e|  Fn |j|  Fd |0|0|0|1|f|g|h|0|i|  Fm | CPDO
+|c o n d|1 1 1 0|a|b|c|L|e|  Fn |   Rd  |0|0|0|1|f|g|h|1|i|  Fm | CPRT
+|c o n d|1 1 1 0|a|b|c|1|e|  Fn |1|1|1|1|0|0|0|1|f|g|h|1|i|  Fm | comparisons
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+
+CPDT           data transfer instructions
+               LDF, STF, LFM, SFM
+               
+CPDO           dyadic arithmetic instructions
+               ADF, MUF, SUF, RSF, DVF, RDF,
+               POW, RPW, RMF, FML, FDV, FRD, POL
+
+CPDO           monadic arithmetic instructions
+               MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
+               SIN, COS, TAN, ASN, ACS, ATN, URD, NRM
+               
+CPRT           joint arithmetic/data transfer instructions
+               FIX (arithmetic followed by load/store)
+               FLT (load/store followed by arithmetic)
+               CMF, CNF CMFE, CNFE (comparisons)
+               WFS, RFS (write/read floating point status register)
+               WFC, RFC (write/read floating point control register)
+
+cond           condition codes
+P              pre/post index bit: 0 = postindex, 1 = preindex
+U              up/down bit: 0 = stack grows down, 1 = stack grows up
+W              write back bit: 1 = update base register (Rn)
+L              load/store bit: 0 = store, 1 = load
+Rn             base register
+Rd             destination/source register             
+Fd             floating point destination register
+Fn             floating point source register
+Fm             floating point source register or floating point constant
+
+uv             transfer length (TABLE 1)
+wx             register count (TABLE 2)
+abcd           arithmetic opcode (TABLES 3 & 4)
+ef             destination size (rounding precision) (TABLE 5)
+gh             rounding mode (TABLE 6)
+j              dyadic/monadic bit: 0 = dyadic, 1 = monadic
+i              constant bit: 1 = constant (TABLE 6)
+*/
+
+/*
+TABLE 1
++-------------------------+---+---+---------+---------+
+|  Precision              | u | v | FPSR.EP | length  |
++-------------------------+---+---+---------+---------+
+| Single                  | 0 Ã¼ 0 |    x    | 1 words |
+| Double                  | 1 Ã¼ 1 |    x    | 2 words |
+| Extended                | 1 Ã¼ 1 |    x    | 3 words |
+| Packed decimal          | 1 Ã¼ 1 |    0    | 3 words |
+| Expanded packed decimal | 1 Ã¼ 1 |    1    | 4 words |
++-------------------------+---+---+---------+---------+
+Note: x = don't care
+*/
+
+/*
+TABLE 2
++---+---+---------------------------------+
+| w | x | Number of registers to transfer |
++---+---+---------------------------------+
+| 0 Ã¼ 1 |  1                              |
+| 1 Ã¼ 0 |  2                              |
+| 1 Ã¼ 1 |  3                              |
+| 0 Ã¼ 0 |  4                              |
++---+---+---------------------------------+
+*/
+
+/*
+TABLE 3: Dyadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description           | Operation             |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | ADF      | Add                   | Fd := Fn + Fm         |
+| 0 | 0 | 0 | 1 | MUF      | Multiply              | Fd := Fn * Fm         |
+| 0 | 0 | 1 | 0 | SUF      | Subtract              | Fd := Fn - Fm         |
+| 0 | 0 | 1 | 1 | RSF      | Reverse subtract      | Fd := Fm - Fn         |
+| 0 | 1 | 0 | 0 | DVF      | Divide                | Fd := Fn / Fm         |
+| 0 | 1 | 0 | 1 | RDF      | Reverse divide        | Fd := Fm / Fn         |
+| 0 | 1 | 1 | 0 | POW      | Power                 | Fd := Fn ^ Fm         |
+| 0 | 1 | 1 | 1 | RPW      | Reverse power         | Fd := Fm ^ Fn         |
+| 1 | 0 | 0 | 0 | RMF      | Remainder             | Fd := IEEE rem(Fn/Fm) |
+| 1 | 0 | 0 | 1 | FML      | Fast Multiply         | Fd := Fn * Fm         |
+| 1 | 0 | 1 | 0 | FDV      | Fast Divide           | Fd := Fn / Fm         |
+| 1 | 0 | 1 | 1 | FRD      | Fast reverse divide   | Fd := Fm / Fn         |
+| 1 | 1 | 0 | 0 | POL      | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm)  |
+| 1 | 1 | 0 | 1 |          | undefined instruction | trap                  |
+| 1 | 1 | 1 | 0 |          | undefined instruction | trap                  |
+| 1 | 1 | 1 | 1 |          | undefined instruction | trap                  |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: POW, RPW, POL are deprecated, and are available for backwards
+      compatibility only.
+*/
+
+/*
+TABLE 4: Monadic Floating Point Opcodes
++---+---+---+---+----------+-----------------------+-----------------------+
+| a | b | c | d | Mnemonic | Description           | Operation             |
++---+---+---+---+----------+-----------------------+-----------------------+
+| 0 | 0 | 0 | 0 | MVF      | Move                  | Fd := Fm              |
+| 0 | 0 | 0 | 1 | MNF      | Move negated          | Fd := - Fm            |
+| 0 | 0 | 1 | 0 | ABS      | Absolute value        | Fd := abs(Fm)         |
+| 0 | 0 | 1 | 1 | RND      | Round to integer      | Fd := int(Fm)         |
+| 0 | 1 | 0 | 0 | SQT      | Square root           | Fd := sqrt(Fm)        |
+| 0 | 1 | 0 | 1 | LOG      | Log base 10           | Fd := log10(Fm)       |
+| 0 | 1 | 1 | 0 | LGN      | Log base e            | Fd := ln(Fm)          |
+| 0 | 1 | 1 | 1 | EXP      | Exponent              | Fd := e ^ Fm          |
+| 1 | 0 | 0 | 0 | SIN      | Sine                  | Fd := sin(Fm)         |
+| 1 | 0 | 0 | 1 | COS      | Cosine                | Fd := cos(Fm)         |
+| 1 | 0 | 1 | 0 | TAN      | Tangent               | Fd := tan(Fm)         |
+| 1 | 0 | 1 | 1 | ASN      | Arc Sine              | Fd := arcsin(Fm)      |
+| 1 | 1 | 0 | 0 | ACS      | Arc Cosine            | Fd := arccos(Fm)      |
+| 1 | 1 | 0 | 1 | ATN      | Arc Tangent           | Fd := arctan(Fm)      |
+| 1 | 1 | 1 | 0 | URD      | Unnormalized round    | Fd := int(Fm)         |
+| 1 | 1 | 1 | 1 | NRM      | Normalize             | Fd := norm(Fm)        |
++---+---+---+---+----------+-----------------------+-----------------------+
+Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are
+      available for backwards compatibility only.
+*/
+
+/*
+TABLE 5
++-------------------------+---+---+
+|  Rounding Precision     | e | f |
++-------------------------+---+---+
+| IEEE Single precision   | 0 Ã¼ 0 |
+| IEEE Double precision   | 0 Ã¼ 1 |
+| IEEE Extended precision | 1 Ã¼ 0 |
+| undefined (trap)        | 1 Ã¼ 1 |
++-------------------------+---+---+
+*/
+
+/*
+TABLE 5
++---------------------------------+---+---+
+|  Rounding Mode                  | g | h |
++---------------------------------+---+---+
+| Round to nearest (default)      | 0 Ã¼ 0 |
+| Round toward plus infinity      | 0 Ã¼ 1 |
+| Round toward negative infinity  | 1 Ã¼ 0 |
+| Round toward zero               | 1 Ã¼ 1 |
++---------------------------------+---+---+
+*/
+
+/*
+===
+=== Definitions for load and store instructions
+===
+*/
+
+/* bit masks */
+#define BIT_PREINDEX   0x01000000
+#define BIT_UP         0x00800000
+#define BIT_WRITE_BACK 0x00200000
+#define BIT_LOAD       0x00100000
+
+/* masks for load/store */
+#define MASK_CPDT              0x0c000000  /* data processing opcode */
+#define MASK_OFFSET            0x000000ff
+#define MASK_TRANSFER_LENGTH   0x00408000
+#define MASK_REGISTER_COUNT    MASK_TRANSFER_LENGTH
+#define MASK_COPROCESSOR       0x00000f00
+
+/* Tests for transfer length */
+#define TRANSFER_SINGLE                0x00000000
+#define TRANSFER_DOUBLE                0x00008000
+#define TRANSFER_EXTENDED      0x00400000
+#define TRANSFER_PACKED                MASK_TRANSFER_LENGTH
+
+/* Get the coprocessor number from the opcode. */
+#define getCoprocessorNumber(opcode)   ((opcode & MASK_COPROCESSOR) >> 8)
+
+/* Get the offset from the opcode. */
+#define getOffset(opcode)              (opcode & MASK_OFFSET)
+
+/* Tests for specific data transfer load/store opcodes. */
+#define TEST_OPCODE(opcode,mask)       (((opcode) & (mask)) == (mask))
+
+#define LOAD_OP(opcode)   TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD)
+#define STORE_OP(opcode)  ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT)
+
+#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1))
+#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2))
+
+#define PREINDEXED(opcode)             ((opcode & BIT_PREINDEX) != 0)
+#define POSTINDEXED(opcode)            ((opcode & BIT_PREINDEX) == 0)
+#define BIT_UP_SET(opcode)             ((opcode & BIT_UP) != 0)
+#define BIT_UP_CLEAR(opcode)           ((opcode & BIT_DOWN) == 0)
+#define WRITE_BACK(opcode)             ((opcode & BIT_WRITE_BACK) != 0)
+#define LOAD(opcode)                   ((opcode & BIT_LOAD) != 0)
+#define STORE(opcode)                  ((opcode & BIT_LOAD) == 0)
+
+/*
+===
+=== Definitions for arithmetic instructions
+===
+*/
+/* bit masks */
+#define BIT_MONADIC    0x00008000
+#define BIT_CONSTANT   0x00000008
+
+#define CONSTANT_FM(opcode)            ((opcode & BIT_CONSTANT) != 0)
+#define MONADIC_INSTRUCTION(opcode)    ((opcode & BIT_MONADIC) != 0)
+
+/* instruction identification masks */
+#define MASK_CPDO              0x0e000000  /* arithmetic opcode */
+#define MASK_ARITHMETIC_OPCODE 0x00f08000
+#define MASK_DESTINATION_SIZE  0x00080080
+
+/* dyadic arithmetic opcodes. */
+#define ADF_CODE       0x00000000
+#define MUF_CODE       0x00100000
+#define SUF_CODE       0x00200000
+#define RSF_CODE       0x00300000
+#define DVF_CODE       0x00400000
+#define RDF_CODE       0x00500000
+#define POW_CODE       0x00600000
+#define RPW_CODE       0x00700000
+#define RMF_CODE       0x00800000
+#define FML_CODE       0x00900000
+#define FDV_CODE       0x00a00000
+#define FRD_CODE       0x00b00000
+#define POL_CODE       0x00c00000
+/* 0x00d00000 is an invalid dyadic arithmetic opcode */
+/* 0x00e00000 is an invalid dyadic arithmetic opcode */
+/* 0x00f00000 is an invalid dyadic arithmetic opcode */
+
+/* monadic arithmetic opcodes. */
+#define MVF_CODE       0x00008000
+#define MNF_CODE       0x00108000
+#define ABS_CODE       0x00208000
+#define RND_CODE       0x00308000
+#define SQT_CODE       0x00408000
+#define LOG_CODE       0x00508000
+#define LGN_CODE       0x00608000
+#define EXP_CODE       0x00708000
+#define SIN_CODE       0x00808000
+#define COS_CODE       0x00908000
+#define TAN_CODE       0x00a08000
+#define ASN_CODE       0x00b08000
+#define ACS_CODE       0x00c08000
+#define ATN_CODE       0x00d08000
+#define URD_CODE       0x00e08000
+#define NRM_CODE       0x00f08000
+
+/*
+===
+=== Definitions for register transfer and comparison instructions
+===
+*/
+
+#define MASK_CPRT              0x0e000010  /* register transfer opcode */
+#define MASK_CPRT_CODE         0x00f00000
+#define FLT_CODE               0x00000000
+#define FIX_CODE               0x00100000
+#define WFS_CODE               0x00200000
+#define RFS_CODE               0x00300000
+#define WFC_CODE               0x00400000
+#define RFC_CODE               0x00500000
+#define CMF_CODE               0x00900000
+#define CNF_CODE               0x00b00000
+#define CMFE_CODE              0x00d00000
+#define CNFE_CODE              0x00f00000
+
+/*
+===
+=== Common definitions
+===
+*/
+
+/* register masks */
+#define MASK_Rd                0x0000f000
+#define MASK_Rn                0x000f0000
+#define MASK_Fd                0x00007000
+#define MASK_Fm                0x00000007
+#define MASK_Fn                0x00070000
+
+/* condition code masks */
+#define CC_MASK                0xf0000000
+#define CC_NEGATIVE    0x80000000
+#define CC_ZERO                0x40000000
+#define CC_CARRY       0x20000000
+#define CC_OVERFLOW    0x10000000
+#define CC_EQ          0x00000000
+#define CC_NE          0x10000000
+#define CC_CS          0x20000000
+#define CC_HS          CC_CS
+#define CC_CC          0x30000000
+#define CC_LO          CC_CC
+#define CC_MI          0x40000000
+#define CC_PL          0x50000000
+#define CC_VS          0x60000000
+#define CC_VC          0x70000000
+#define CC_HI          0x80000000
+#define CC_LS          0x90000000
+#define CC_GE          0xa0000000
+#define CC_LT          0xb0000000
+#define CC_GT          0xc0000000
+#define CC_LE          0xd0000000
+#define CC_AL          0xe0000000
+#define CC_NV          0xf0000000
+
+/* rounding masks/values */
+#define MASK_ROUNDING_MODE     0x00000060
+#define ROUND_TO_NEAREST       0x00000000
+#define ROUND_TO_PLUS_INFINITY 0x00000020
+#define ROUND_TO_MINUS_INFINITY        0x00000040
+#define ROUND_TO_ZERO          0x00000060
+
+#define MASK_ROUNDING_PRECISION        0x00080080
+#define ROUND_SINGLE           0x00000000
+#define ROUND_DOUBLE           0x00000080
+#define ROUND_EXTENDED         0x00080000
+
+/* Get the condition code from the opcode. */
+#define getCondition(opcode)           (opcode >> 28)
+
+/* Get the source register from the opcode. */
+#define getRn(opcode)                  ((opcode & MASK_Rn) >> 16)
+
+/* Get the destination floating point register from the opcode. */
+#define getFd(opcode)                  ((opcode & MASK_Fd) >> 12)
+
+/* Get the first source floating point register from the opcode. */
+#define getFn(opcode)          ((opcode & MASK_Fn) >> 16)
+
+/* Get the second source floating point register from the opcode. */
+#define getFm(opcode)          (opcode & MASK_Fm)
+
+/* Get the destination register from the opcode. */
+#define getRd(opcode)          ((opcode & MASK_Rd) >> 12)
+
+/* Get the rounding mode from the opcode. */
+#define getRoundingMode(opcode)                ((opcode & MASK_ROUNDING_MODE) >> 5)
+
+float32 getSingleConstant(const unsigned int nIndex);
+float64 getDoubleConstant(const unsigned int nIndex);
+floatx80 getExtendedConstant(const unsigned int nIndex);
+
+unsigned int getRegisterCount(const unsigned int opcode);
+unsigned int getDestinationSize(const unsigned int opcode);
+
+#endif
diff --git a/arch/arm/nwfpe/fpsr.h b/arch/arm/nwfpe/fpsr.h
new file mode 100644 (file)
index 0000000..f58994a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __FPSR_H__
+#define __FPSR_H__
+
+/*
+The FPSR is a 32 bit register consisting of 4 parts, each exactly
+one byte.
+
+       SYSTEM ID
+       EXCEPTION TRAP ENABLE BYTE
+       SYSTEM CONTROL BYTE
+       CUMULATIVE EXCEPTION FLAGS BYTE
+       
+The FPCR is a 32 bit register consisting of bit flags.
+*/
+
+/* SYSTEM ID
+------------
+Note: the system id byte is read only  */
+
+typedef unsigned int FPSR;  /* type for floating point status register */
+typedef unsigned int FPCR;  /* type for floating point control register */
+
+#define MASK_SYSID             0xff000000
+#define BIT_HARDWARE           0x80000000
+#define FP_EMULATOR            0x01000000      /* System ID for emulator */ 
+#define FP_ACCELERATOR         0x81000000      /* System ID for FPA11 */
+
+/* EXCEPTION TRAP ENABLE BYTE
+----------------------------- */
+
+#define MASK_TRAP_ENABLE       0x00ff0000
+#define MASK_TRAP_ENABLE_STRICT        0x001f0000
+#define BIT_IXE                0x00100000   /* inexact exception enable */
+#define BIT_UFE                0x00080000   /* underflow exception enable */
+#define BIT_OFE                0x00040000   /* overflow exception enable */
+#define BIT_DZE                0x00020000   /* divide by zero exception enable */
+#define BIT_IOE                0x00010000   /* invalid operation exception enable */
+
+/* SYSTEM CONTROL BYTE
+---------------------- */
+
+#define MASK_SYSTEM_CONTROL    0x0000ff00
+#define MASK_TRAP_STRICT       0x00001f00
+
+#define BIT_AC 0x00100000      /* use alternative C-flag definition
+                                  for compares */
+#define BIT_EP 0x00080000      /* use expanded packed decimal format */
+#define BIT_SO 0x00040000      /* select synchronous operation of FPA */
+#define BIT_NE 0x00020000      /* NaN exception bit */
+#define BIT_ND 0x00010000      /* no denormalized numbers bit */
+
+/* CUMULATIVE EXCEPTION FLAGS BYTE
+---------------------------------- */
+
+#define MASK_EXCEPTION_FLAGS           0x000000ff
+#define MASK_EXCEPTION_FLAGS_STRICT    0x0000001f
+
+#define BIT_IXC                0x00000010      /* inexact exception flag */
+#define BIT_UFC                0x00000008      /* underflow exception flag */
+#define BIT_OFC                0x00000004      /* overfloat exception flag */
+#define BIT_DZC                0x00000002      /* divide by zero exception flag */
+#define BIT_IOC                0x00000001      /* invalid operation exception flag */
+
+/* Floating Point Control Register
+----------------------------------*/
+
+#define BIT_RU         0x80000000      /* rounded up bit */
+#define BIT_IE         0x10000000      /* inexact bit */
+#define BIT_MO         0x08000000      /* mantissa overflow bit */
+#define BIT_EO         0x04000000      /* exponent overflow bit */
+#define BIT_SB         0x00000800      /* store bounce */
+#define BIT_AB         0x00000400      /* arithmetic bounce */
+#define BIT_RE         0x00000200      /* rounding exception */
+#define BIT_DA         0x00000100      /* disable FPA */
+
+#define MASK_OP                0x00f08010      /* AU operation code */
+#define MASK_PR                0x00080080      /* AU precision */
+#define MASK_S1                0x00070000      /* AU source register 1 */
+#define MASK_S2                0x00000007      /* AU source register 2 */
+#define MASK_DS                0x00007000      /* AU destination register */
+#define MASK_RM                0x00000060      /* AU rounding mode */
+#define MASK_ALU       0x9cfff2ff      /* only ALU can write these bits */
+#define MASK_RESET     0x00000d00      /* bits set on reset, all others cleared */
+#define MASK_WFC       MASK_RESET
+#define MASK_RFC       ~MASK_RESET
+
+#endif
diff --git a/arch/arm/nwfpe/milieu.h b/arch/arm/nwfpe/milieu.h
new file mode 100644 (file)
index 0000000..a3892ab
--- /dev/null
@@ -0,0 +1,48 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "ARM-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+    FALSE = 0,
+    TRUE  = 1
+};
+
diff --git a/arch/arm/nwfpe/single_cpdo.c b/arch/arm/nwfpe/single_cpdo.c
new file mode 100644 (file)
index 0000000..f8405ee
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+    NetWinder Floating Point Emulator
+    (c) Corel Computer Corporation, 1998
+
+    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include "milieu.h"
+#include "softfloat.h"
+#include "fpopcode.h"
+#include "fpa11.h"
+
+float32 getSingleConstant(unsigned int);
+
+float32 float32_exp(float32 Fm);
+float32 float32_ln(float32 Fm);
+float32 float32_sin(float32 rFm);
+float32 float32_cos(float32 rFm);
+float32 float32_arcsin(float32 rFm);
+float32 float32_arctan(float32 rFm);
+float32 float32_log(float32 rFm);
+float32 float32_tan(float32 rFm);
+float32 float32_arccos(float32 rFm);
+float32 float32_pow(float32 rFn,float32 rFm);
+float32 float32_pol(float32 rFn,float32 rFm);
+
+unsigned int SingleCPDO(const unsigned int opcode)
+{
+   float32 rFm, rFn;
+   unsigned int Fd, Fm, Fn, nRc = 1;
+
+   Fm = getFm(opcode);
+   if (CONSTANT_FM(opcode))
+   {
+     rFm = getSingleConstant(Fm);
+   }
+   else
+   {  
+     switch (fpa11->fpreg[Fm].fType)
+     {
+        case typeSingle:
+          rFm = fpa11->fpreg[Fm].fValue.fSingle;
+        break;
+        
+        default: return 0;
+     }
+   }
+
+   if (!MONADIC_INSTRUCTION(opcode))
+   {
+      Fn = getFn(opcode);
+      switch (fpa11->fpreg[Fn].fType)
+      {
+        case typeSingle:
+          rFn = fpa11->fpreg[Fn].fValue.fSingle;
+        break;
+
+        default: return 0;
+      }
+   }
+
+   Fd = getFd(opcode);
+   switch (opcode & MASK_ARITHMETIC_OPCODE)
+   {
+      /* dyadic opcodes */
+      case ADF_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm);
+      break;
+
+      case MUF_CODE:
+      case FML_CODE:
+        fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm);
+      break;
+
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm);
+      break;
+
+      case RSF_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn);
+      break;
+
+      case DVF_CODE:
+      case FDV_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm);
+      break;
+
+      case RDF_CODE:
+      case FRD_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn);
+      break;
+
+#if 0
+      case POW_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm);
+      break;
+
+      case RPW_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn);
+      break;
+#endif
+
+      case RMF_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm);
+      break;
+
+#if 0
+      case POL_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm);
+      break;
+#endif
+
+      /* monadic opcodes */
+      case MVF_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+      break;
+
+      case MNF_CODE:
+         rFm ^= 0x80000000;
+         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+      break;
+
+      case ABS_CODE:
+         rFm &= 0x7fffffff;
+         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+      break;
+
+      case RND_CODE:
+      case URD_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = 
+             int32_to_float32(float32_to_int32(rFm));
+      break;
+
+      case SQT_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm);
+      break;
+
+#if 0
+      case LOG_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm);
+      break;
+
+      case LGN_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm);
+      break;
+
+      case EXP_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm);
+      break;
+
+      case SIN_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm);
+      break;
+
+      case COS_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm);
+      break;
+
+      case TAN_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm);
+      break;
+
+      case ASN_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm);
+      break;
+
+      case ACS_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm);
+      break;
+
+      case ATN_CODE:
+         fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm);
+      break;
+#endif
+
+      case NRM_CODE:
+      break;
+      
+      default:
+      {
+        nRc = 0;
+      }
+   }
+
+   if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle;
+   return nRc;
+}
+
+#if 0
+float32 float32_exp(float32 Fm)
+{
+//series
+}
+
+float32 float32_ln(float32 Fm)
+{
+//series
+}
+
+float32 float32_sin(float32 rFm)
+{
+//series
+}
+
+float32 float32_cos(float32 rFm)
+{
+//series
+}
+
+float32 float32_arcsin(float32 rFm)
+{
+//series
+}
+
+float32 float32_arctan(float32 rFm)
+{
+  //series
+}
+
+float32 float32_arccos(float32 rFm)
+{
+   //return float32_sub(halfPi,float32_arcsin(rFm));
+}
+
+float32 float32_log(float32 rFm)
+{
+  return float32_div(float32_ln(rFm),getSingleConstant(7));
+}
+
+float32 float32_tan(float32 rFm)
+{
+  return float32_div(float32_sin(rFm),float32_cos(rFm));
+}
+
+float32 float32_pow(float32 rFn,float32 rFm)
+{
+  return float32_exp(float32_mul(rFm,float32_ln(rFn))); 
+}
+
+float32 float32_pol(float32 rFn,float32 rFm)
+{
+  return float32_arctan(float32_div(rFn,rFm)); 
+}
+#endif
diff --git a/arch/arm/nwfpe/softfloat-macros b/arch/arm/nwfpe/softfloat-macros
new file mode 100644 (file)
index 0000000..5469989
--- /dev/null
@@ -0,0 +1,740 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'.  If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1.  The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 32, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+{
+    bits32 z;
+    if ( count == 0 ) {
+        z = a;
+    }
+    else if ( count < 32 ) {
+        z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+    }
+    else {
+        z = ( a != 0 );
+    }
+    *zPtr = z;
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'.  If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1.  The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 64, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
+{
+    bits64 z;
+
+ __asm__("@shift64RightJamming -- start");   
+    if ( count == 0 ) {
+        z = a;
+    }
+    else if ( count < 64 ) {
+        z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
+    }
+    else {
+        z = ( a != 0 );
+    }
+ __asm__("@shift64RightJamming -- end");   
+    *zPtr = z;
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
+_plus_ the number of bits given in `count'.  The shifted result is at most
+64 nonzero bits; this is stored at the location pointed to by `z0Ptr'.  The
+bits shifted off form a second 64-bit result as follows:  The _last_ bit
+shifted off is the most-significant bit of the extra result, and the other
+63 bits of the extra result are all zero if and only if _all_but_the_last_
+bits shifted off were all zero.  This extra result is stored in the location
+pointed to by `z1Ptr'.  The value of `count' can be arbitrarily large.
+    (This routine makes more sense if `a0' and `a1' are considered to form a
+fixed-point value with binary point between `a0' and `a1'.  This fixed-point
+value is shifted right by the number of bits given in `count', and the
+integer part of the result is returned at the location pointed to by
+`z0Ptr'.  The fractional part of the result may be slightly corrupted as
+described above, and is returned at the location pointed to by `z1Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64ExtraRightJamming(
+     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+    bits64 z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1 != 0 );
+        z0 = a0>>count;
+    }
+    else {
+        if ( count == 64 ) {
+            z1 = a0 | ( a1 != 0 );
+        }
+        else {
+            z1 = ( ( a0 | a1 ) != 0 );
+        }
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'.  Any bits shifted off are lost.  The value
+of `count' can be arbitrarily large; in particular, if `count' is greater
+than 128, the result will be 0.  The result is broken into two 64-bit pieces
+which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128Right(
+     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+    bits64 z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count );
+        z0 = a0>>count;
+    }
+    else {
+        z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'.  If any nonzero bits are shifted off, they
+are ``jammed'' into the least significant bit of the result by setting the
+least significant bit to 1.  The value of `count' can be arbitrarily large;
+in particular, if `count' is greater than 128, the result will be either 0
+or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+nonzero.  The result is broken into two 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128RightJamming(
+     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+    bits64 z0, z1;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 64 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
+        z0 = a0>>count;
+    }
+    else {
+        if ( count == 64 ) {
+            z1 = a0 | ( a1 != 0 );
+        }
+        else if ( count < 128 ) {
+            z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
+        }
+        else {
+            z1 = ( ( a0 | a1 ) != 0 );
+        }
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
+by 64 _plus_ the number of bits given in `count'.  The shifted result is
+at most 128 nonzero bits; these are broken into two 64-bit pieces which are
+stored at the locations pointed to by `z0Ptr' and `z1Ptr'.  The bits shifted
+off form a third 64-bit result as follows:  The _last_ bit shifted off is
+the most-significant bit of the extra result, and the other 63 bits of the
+extra result are all zero if and only if _all_but_the_last_ bits shifted off
+were all zero.  This extra result is stored in the location pointed to by
+`z2Ptr'.  The value of `count' can be arbitrarily large.
+    (This routine makes more sense if `a0', `a1', and `a2' are considered
+to form a fixed-point value with binary point between `a1' and `a2'.  This
+fixed-point value is shifted right by the number of bits given in `count',
+and the integer part of the result is returned at the locations pointed to
+by `z0Ptr' and `z1Ptr'.  The fractional part of the result may be slightly
+corrupted as described above, and is returned at the location pointed to by
+`z2Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128ExtraRightJamming(
+     bits64 a0,
+     bits64 a1,
+     bits64 a2,
+     int16 count,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr
+ )
+{
+    bits64 z0, z1, z2;
+    int8 negCount = ( - count ) & 63;
+
+    if ( count == 0 ) {
+        z2 = a2;
+        z1 = a1;
+        z0 = a0;
+    }
+    else {
+        if ( count < 64 ) {
+            z2 = a1<<negCount;
+            z1 = ( a0<<negCount ) | ( a1>>count );
+            z0 = a0>>count;
+        }
+        else {
+            if ( count == 64 ) {
+                z2 = a1;
+                z1 = a0;
+            }
+            else {
+                a2 |= a1;
+                if ( count < 128 ) {
+                    z2 = a0<<negCount;
+                    z1 = a0>>( count & 63 );
+                }
+                else {
+                    z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
+                    z1 = 0;
+                }
+            }
+            z0 = 0;
+        }
+        z2 |= ( a2 != 0 );
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
+number of bits given in `count'.  Any bits shifted off are lost.  The value
+of `count' must be less than 64.  The result is broken into two 64-bit
+pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift128Left(
+     bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+    *z1Ptr = a1<<count;
+    *z0Ptr =
+        ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
+by the number of bits given in `count'.  Any bits shifted off are lost.
+The value of `count' must be less than 64.  The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift192Left(
+     bits64 a0,
+     bits64 a1,
+     bits64 a2,
+     int16 count,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr
+ )
+{
+    bits64 z0, z1, z2;
+    int8 negCount;
+
+    z2 = a2<<count;
+    z1 = a1<<count;
+    z0 = a0<<count;
+    if ( 0 < count ) {
+        negCount = ( ( - count ) & 63 );
+        z1 |= a2>>negCount;
+        z0 |= a1>>negCount;
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
+value formed by concatenating `b0' and `b1'.  Addition is modulo 2^128, so
+any carry out is lost.  The result is broken into two 64-bit pieces which
+are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add128(
+     bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+    bits64 z1;
+
+    z1 = a1 + b1;
+    *z1Ptr = z1;
+    *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
+192-bit value formed by concatenating `b0', `b1', and `b2'.  Addition is
+modulo 2^192, so any carry out is lost.  The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add192(
+     bits64 a0,
+     bits64 a1,
+     bits64 a2,
+     bits64 b0,
+     bits64 b1,
+     bits64 b2,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr
+ )
+{
+    bits64 z0, z1, z2;
+    int8 carry0, carry1;
+
+    z2 = a2 + b2;
+    carry1 = ( z2 < a2 );
+    z1 = a1 + b1;
+    carry0 = ( z1 < a1 );
+    z0 = a0 + b0;
+    z1 += carry1;
+    z0 += ( z1 < carry1 );
+    z0 += carry0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
+128-bit value formed by concatenating `a0' and `a1'.  Subtraction is modulo
+2^128, so any borrow out (carry out) is lost.  The result is broken into two
+64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+`z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub128(
+     bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+    *z1Ptr = a1 - b1;
+    *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
+from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
+Subtraction is modulo 2^192, so any borrow out (carry out) is lost.  The
+result is broken into three 64-bit pieces which are stored at the locations
+pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub192(
+     bits64 a0,
+     bits64 a1,
+     bits64 a2,
+     bits64 b0,
+     bits64 b1,
+     bits64 b2,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr
+ )
+{
+    bits64 z0, z1, z2;
+    int8 borrow0, borrow1;
+
+    z2 = a2 - b2;
+    borrow1 = ( a2 < b2 );
+    z1 = a1 - b1;
+    borrow0 = ( a1 < b1 );
+    z0 = a0 - b0;
+    z0 -= ( z1 < borrow1 );
+    z1 -= borrow1;
+    z0 -= borrow0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies `a' by `b' to obtain a 128-bit product.  The product is broken
+into two 64-bit pieces which are stored at the locations pointed to by
+`z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+    bits32 aHigh, aLow, bHigh, bLow;
+    bits64 z0, zMiddleA, zMiddleB, z1;
+
+    aLow = a;
+    aHigh = a>>32;
+    bLow = b;
+    bHigh = b>>32;
+    z1 = ( (bits64) aLow ) * bLow;
+    zMiddleA = ( (bits64) aLow ) * bHigh;
+    zMiddleB = ( (bits64) aHigh ) * bLow;
+    z0 = ( (bits64) aHigh ) * bHigh;
+    zMiddleA += zMiddleB;
+    z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
+    zMiddleA <<= 32;
+    z1 += zMiddleA;
+    z0 += ( z1 < zMiddleA );
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to
+obtain a 192-bit product.  The product is broken into three 64-bit pieces
+which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+`z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128By64To192(
+     bits64 a0,
+     bits64 a1,
+     bits64 b,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr
+ )
+{
+    bits64 z0, z1, z2, more1;
+
+    mul64To128( a1, b, &z1, &z2 );
+    mul64To128( a0, b, &z0, &more1 );
+    add128( z0, more1, 0, z1, &z0, &z1 );
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
+128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
+product.  The product is broken into four 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128To256(
+     bits64 a0,
+     bits64 a1,
+     bits64 b0,
+     bits64 b1,
+     bits64 *z0Ptr,
+     bits64 *z1Ptr,
+     bits64 *z2Ptr,
+     bits64 *z3Ptr
+ )
+{
+    bits64 z0, z1, z2, z3;
+    bits64 more1, more2;
+
+    mul64To128( a1, b1, &z2, &z3 );
+    mul64To128( a1, b0, &z1, &more2 );
+    add128( z1, more2, 0, z2, &z1, &z2 );
+    mul64To128( a0, b0, &z0, &more1 );
+    add128( z0, more1, 0, z1, &z0, &z1 );
+    mul64To128( a0, b1, &more1, &more2 );
+    add128( more1, more2, 0, z2, &more1, &z2 );
+    add128( z0, z1, 0, more1, &z0, &z1 );
+    *z3Ptr = z3;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the 64-bit integer quotient obtained by dividing
+`b' into the 128-bit value formed by concatenating `a0' and `a1'.  The
+divisor `b' must be at least 2^63.  If q is the exact quotient truncated
+toward zero, the approximation returned lies between q and q + 2 inclusive.
+If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
+unsigned integer is returned.
+-------------------------------------------------------------------------------
+*/
+static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
+{
+    bits64 b0, b1;
+    bits64 rem0, rem1, term0, term1;
+    bits64 z;
+    if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
+    b0 = b>>32;
+    z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
+    mul64To128( b, z, &term0, &term1 );
+    sub128( a0, a1, term0, term1, &rem0, &rem1 );
+    while ( ( (sbits64) rem0 ) < 0 ) {
+        z -= LIT64( 0x100000000 );
+        b1 = b<<32;
+        add128( rem0, rem1, b0, b1, &rem0, &rem1 );
+    }
+    rem0 = ( rem0<<32 ) | ( rem1>>32 );
+    z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the square root of the 32-bit significand given
+by `a'.  Considered as an integer, `a' must be at least 2^31.  If bit 0 of
+`aExp' (the least significant bit) is 1, the integer returned approximates
+2^31*sqrt(`a'/2^31), where `a' is considered an integer.  If bit 0 of `aExp'
+is 0, the integer returned approximates 2^31*sqrt(`a'/2^30).  In either
+case, the approximation returned lies strictly within +/-2 of the exact
+value.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateSqrt32( int16 aExp, bits32 a )
+{
+    static const bits16 sqrtOddAdjustments[] = {
+        0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+        0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+    };
+    static const bits16 sqrtEvenAdjustments[] = {
+        0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+        0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+    };
+    int8 index;
+    bits32 z;
+
+    index = ( a>>27 ) & 15;
+    if ( aExp & 1 ) {
+        z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+        z = ( ( a / z )<<14 ) + ( z<<15 );
+        a >>= 1;
+    }
+    else {
+        z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+        z = a / z + z;
+        z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+        if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+    }
+    return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit
+of `a'.  If `a' is zero, 32 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros32( bits32 a )
+{
+    static const int8 countLeadingZerosHigh[] = {
+        8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    int8 shiftCount;
+
+    shiftCount = 0;
+    if ( a < 0x10000 ) {
+        shiftCount += 16;
+        a <<= 16;
+    }
+    if ( a < 0x1000000 ) {
+        shiftCount += 8;
+        a <<= 8;
+    }
+    shiftCount += countLeadingZerosHigh[ a>>24 ];
+    return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit
+of `a'.  If `a' is zero, 64 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros64( bits64 a )
+{
+    int8 shiftCount;
+
+    shiftCount = 0;
+    if ( a < ( (bits64) 1 )<<32 ) {
+        shiftCount += 32;
+    }
+    else {
+        a >>= 32;
+    }
+    shiftCount += countLeadingZeros32( a );
+    return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
+is equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+    return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than the 128-bit value formed by concatenating `b0' and `b1'.  Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
+not equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+    return ( a0 != b0 ) || ( a1 != b1 );
+
+}
+
diff --git a/arch/arm/nwfpe/softfloat-specialize b/arch/arm/nwfpe/softfloat-specialize
new file mode 100644 (file)
index 0000000..f03e5c6
--- /dev/null
@@ -0,0 +1,471 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Underflow tininess-detection mode, statically initialized to default value.
+(The declaration in `softfloat.h' must match the `int8' type here.)
+-------------------------------------------------------------------------------
+*/
+int8 float_detect_tininess = float_tininess_after_rounding;
+
+/*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'.  Floating-point traps can be
+defined here if desired.  It is currently not possible for such a trap to
+substitute a result value.  If traps are not implemented, this routine
+should be simply `float_exception_flags |= flags;'.
+
+ScottB:  November 4, 1998
+Moved this function out of softfloat-specialize into fpmodule.c.
+This effectively isolates all the changes required for integrating with the
+Linux kernel into fpmodule.c.  Porting to NetBSD should only require modifying
+fpmodule.c to integrate with the NetBSD kernel (I hope!).
+-------------------------------------------------------------------------------
+void float_raise( int8 flags )
+{
+    float_exception_flags |= flags;
+}
+*/
+
+/*
+-------------------------------------------------------------------------------
+Internal canonical NaN format.
+-------------------------------------------------------------------------------
+*/
+typedef struct {
+    flag sign;
+    bits64 high, low;
+} commonNaNT;
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated single-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float32_default_nan 0xFFFFFFFF
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_nan( float32 a )
+{
+
+    return ( 0xFF000000 < (bits32) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_signaling_nan( float32 a )
+{
+
+    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point NaN
+`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float32ToCommonNaN( float32 a )
+{
+    commonNaNT z;
+
+    if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+    z.sign = a>>31;
+    z.low = 0;
+    z.high = ( (bits64) a )<<41;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the single-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float32 commonNaNToFloat32( commonNaNT a )
+{
+
+    return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two single-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float32 propagateFloat32NaN( float32 a, float32 b )
+{
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+    aIsNaN = float32_is_nan( a );
+    aIsSignalingNaN = float32_is_signaling_nan( a );
+    bIsNaN = float32_is_nan( b );
+    bIsSignalingNaN = float32_is_signaling_nan( b );
+    a |= 0x00400000;
+    b |= 0x00400000;
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+    if ( aIsNaN ) {
+        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+    }
+    else {
+        return b;
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated double-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_nan( float64 a )
+{
+
+    return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_signaling_nan( float64 a )
+{
+
+    return
+           ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+        && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point NaN
+`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float64ToCommonNaN( float64 a )
+{
+    commonNaNT z;
+
+    if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+    z.sign = a>>63;
+    z.low = 0;
+    z.high = a<<12;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the double-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float64 commonNaNToFloat64( commonNaNT a )
+{
+
+    return
+          ( ( (bits64) a.sign )<<63 )
+        | LIT64( 0x7FF8000000000000 )
+        | ( a.high>>12 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two double-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float64 propagateFloat64NaN( float64 a, float64 b )
+{
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+    aIsNaN = float64_is_nan( a );
+    aIsSignalingNaN = float64_is_signaling_nan( a );
+    bIsNaN = float64_is_nan( b );
+    bIsSignalingNaN = float64_is_signaling_nan( b );
+    a |= LIT64( 0x0008000000000000 );
+    b |= LIT64( 0x0008000000000000 );
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+    if ( aIsNaN ) {
+        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+    }
+    else {
+        return b;
+    }
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated extended double-precision NaN.  The
+`high' and `low' values hold the most- and least-significant bits,
+respectively.
+-------------------------------------------------------------------------------
+*/
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_nan( floatx80 a )
+{
+
+    return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_signaling_nan( floatx80 a )
+{
+    //register int lr;
+    bits64 aLow;
+
+    //__asm__("mov %0, lr" : : "g" (lr));
+    //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr);
+    aLow = a.low & ~ LIT64( 0x4000000000000000 );
+    return
+           ( ( a.high & 0x7FFF ) == 0x7FFF )
+        && (bits64) ( aLow<<1 )
+        && ( a.low == aLow );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point NaN `a' to the canonical NaN format.  If `a' is a signaling NaN, the
+invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT floatx80ToCommonNaN( floatx80 a )
+{
+    commonNaNT z;
+
+    if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+    z.sign = a.high>>15;
+    z.low = 0;
+    z.high = a.low<<1;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the extended
+double-precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static floatx80 commonNaNToFloatx80( commonNaNT a )
+{
+    floatx80 z;
+
+    z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+    z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two extended double-precision floating-point values `a' and `b', one
+of which is a NaN, and returns the appropriate NaN result.  If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
+{
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+    aIsNaN = floatx80_is_nan( a );
+    aIsSignalingNaN = floatx80_is_signaling_nan( a );
+    bIsNaN = floatx80_is_nan( b );
+    bIsSignalingNaN = floatx80_is_signaling_nan( b );
+    a.low |= LIT64( 0xC000000000000000 );
+    b.low |= LIT64( 0xC000000000000000 );
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+    if ( aIsNaN ) {
+        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+    }
+    else {
+        return b;
+    }
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated quadruple-precision NaN.  The `high' and
+`low' values hold the most- and least-significant bits, respectively.
+-------------------------------------------------------------------------------
+*/
+#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
+#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_nan( float128 a )
+{
+
+    return
+           ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_signaling_nan( float128 a )
+{
+
+    return
+           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point NaN
+`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float128ToCommonNaN( float128 a )
+{
+    commonNaNT z;
+
+    if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+    z.sign = a.high>>63;
+    shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the quadruple-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float128 commonNaNToFloat128( commonNaNT a )
+{
+    float128 z;
+
+    shift128Right( a.high, a.low, 16, &z.high, &z.low );
+    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two quadruple-precision floating-point values `a' and `b', one of
+which is a NaN, and returns the appropriate NaN result.  If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float128 propagateFloat128NaN( float128 a, float128 b )
+{
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+    aIsNaN = float128_is_nan( a );
+    aIsSignalingNaN = float128_is_signaling_nan( a );
+    bIsNaN = float128_is_nan( b );
+    bIsSignalingNaN = float128_is_signaling_nan( b );
+    a.high |= LIT64( 0x0000800000000000 );
+    b.high |= LIT64( 0x0000800000000000 );
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+    if ( aIsNaN ) {
+        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+    }
+    else {
+        return b;
+    }
+
+}
+
+#endif
+
diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
new file mode 100644 (file)
index 0000000..a7fc76c
--- /dev/null
@@ -0,0 +1,4877 @@
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include "milieu.h"
+#include "softfloat.h"
+
+/*
+-------------------------------------------------------------------------------
+Floating-point rounding mode, extended double-precision rounding precision,
+and exception flags.
+-------------------------------------------------------------------------------
+*/
+int8 float_rounding_mode = float_round_nearest_even;
+int8 floatx80_rounding_precision = 80;
+int8 float_exception_flags = 0;
+
+/*
+-------------------------------------------------------------------------------
+Primitive arithmetic functions, including multi-word arithmetic, and
+division and square root approximations.  (Can be specialized to target if
+desired.)
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-macros"
+
+/*
+-------------------------------------------------------------------------------
+Functions and definitions to determine:  (1) whether tininess for underflow
+is detected before or after rounding by default, (2) what (if anything)
+happens when exceptions are raised, (3) how signaling NaNs are distinguished
+from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
+are propagated from function inputs to output.  These details are target-
+specific.
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-specialize"
+
+/*
+-------------------------------------------------------------------------------
+Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
+and 7, and returns the properly rounded 32-bit integer corresponding to the
+input.  If `zSign' is nonzero, the input is negated before being converted
+to an integer.  Bit 63 of `absZ' must be zero.  Ordinarily, the fixed-point
+input is simply rounded to an integer, with the inexact exception raised if
+the input cannot be represented exactly as an integer.  If the fixed-point
+input is too large, however, the invalid exception is raised and the largest
+positive or negative integer is returned.
+-------------------------------------------------------------------------------
+*/
+static int32 roundAndPackInt32( flag zSign, bits64 absZ )
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int8 roundIncrement, roundBits;
+    int32 z;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x40;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x7F;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = absZ & 0x7F;
+    absZ = ( absZ + roundIncrement )>>7;
+    absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+    z = absZ;
+    if ( zSign ) z = - z;
+    if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
+        float_exception_flags |= float_flag_invalid;
+        return zSign ? 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat32Frac( float32 a )
+{
+
+    return a & 0x007FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+    return ( a>>23 ) & 0xFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+    return a>>31;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal single-precision floating-point value represented
+by the denormalized significand `aSig'.  The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( aSig ) - 8;
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+single-precision floating-point value, returning the result.  After being
+shifted into the proper positions, the three fields are simply added
+together to form the result.  This means that any integer portion of `zSig'
+will be added into the exponent.  Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+#if 0
+   float32 f;
+   __asm__("@ packFloat32;
+           mov %0, %1, asl #31;
+           orr %0, %2, asl #23;
+           orr %0, %3"
+           : /* no outputs */
+           : "g" (f), "g" (zSign), "g" (zExp), "g" (zSig)
+           : "cc");
+   return f;
+#else
+    return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
+#endif 
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input.  Ordinarily, the abstract
+value is simply rounded and packed into the single-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly.  If the abstract value is too large, however, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned.  If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal single-
+precision floating-point number.
+    The input significand `zSig' has its binary point between bits 30
+and 29, which is 7 bits to the left of the usual location.  This shifted
+significand must be normalized or smaller.  If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding.  In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int8 roundIncrement, roundBits;
+    flag isTiny;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x40;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x7F;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig & 0x7F;
+    if ( 0xFD <= (bits16) zExp ) {
+        if (    ( 0xFD < zExp )
+             || (    ( zExp == 0xFD )
+                  && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact );
+            return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
+        }
+        if ( zExp < 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ( zSig + roundIncrement < 0x80000000 );
+            shift32RightJamming( zSig, - zExp, &zSig );
+            zExp = 0;
+            roundBits = zSig & 0x7F;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+        }
+    }
+    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    zSig = ( zSig + roundIncrement )>>7;
+    zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+    if ( zSig == 0 ) zExp = 0;
+    return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input.  This routine is just like
+`roundAndPackFloat32' except that `zSig' does not have to be normalized in
+any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( zSig ) - 1;
+    return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat64Frac( float64 a )
+{
+
+    return a & LIT64( 0x000FFFFFFFFFFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat64Exp( float64 a )
+{
+
+    return ( a>>52 ) & 0x7FF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat64Sign( float64 a )
+{
+
+    return a>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal double-precision floating-point value represented
+by the denormalized significand `aSig'.  The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( aSig ) - 11;
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+double-precision floating-point value, returning the result.  After being
+shifted into the proper positions, the three fields are simply added
+together to form the result.  This means that any integer portion of `zSig'
+will be added into the exponent.  Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+
+    return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper double-precision floating-
+point value corresponding to the abstract input.  Ordinarily, the abstract
+value is simply rounded and packed into the double-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly.  If the abstract value is too large, however, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned.  If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal double-
+precision floating-point number.
+    The input significand `zSig' has its binary point between bits 62
+and 61, which is 10 bits to the left of the usual location.  This shifted
+significand must be normalized or smaller.  If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding.  In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int16 roundIncrement, roundBits;
+    flag isTiny;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    roundIncrement = 0x200;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x3FF;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig & 0x3FF;
+    if ( 0x7FD <= (bits16) zExp ) {
+        if (    ( 0x7FD < zExp )
+             || (    ( zExp == 0x7FD )
+                  && ( (sbits64) ( zSig + roundIncrement ) < 0 ) )
+           ) {
+            //register int lr;
+            //__asm__("mov %0, lr" :: "g" (lr));
+            //fp_printk("roundAndPackFloat64 called from 0x%08x\n",lr);
+            float_raise( float_flag_overflow | float_flag_inexact );
+            return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 );
+        }
+        if ( zExp < 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) );
+            shift64RightJamming( zSig, - zExp, &zSig );
+            zExp = 0;
+            roundBits = zSig & 0x3FF;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+        }
+    }
+    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    zSig = ( zSig + roundIncrement )>>10;
+    zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
+    if ( zSig == 0 ) zExp = 0;
+    return packFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper double-precision floating-
+point value corresponding to the abstract input.  This routine is just like
+`roundAndPackFloat64' except that `zSig' does not have to be normalized in
+any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float64
+ normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( zSig ) - 1;
+    return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the extended double-precision floating-point
+value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloatx80Frac( floatx80 a )
+{
+
+    return a.low;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the extended double-precision floating-point
+value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int32 extractFloatx80Exp( floatx80 a )
+{
+
+    return a.high & 0x7FFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the extended double-precision floating-point value
+`a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloatx80Sign( floatx80 a )
+{
+
+    return a.high>>15;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal extended double-precision floating-point value
+represented by the denormalized significand `aSig'.  The normalized exponent
+and significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros64( aSig );
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
+extended double-precision floating-point value, returning the result.
+-------------------------------------------------------------------------------
+*/
+INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
+{
+    floatx80 z;
+
+    z.low = zSig;
+    z.high = ( ( (bits16) zSign )<<15 ) + zExp;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and extended significand formed by the concatenation of `zSig0' and `zSig1',
+and returns the proper extended double-precision floating-point value
+corresponding to the abstract input.  Ordinarily, the abstract value is
+rounded and packed into the extended double-precision format, with the
+inexact exception raised if the abstract input cannot be represented
+exactly.  If the abstract value is too large, however, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned.  If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal extended
+double-precision floating-point number.
+    If `roundingPrecision' is 32 or 64, the result is rounded to the same
+number of bits as single or double precision, respectively.  Otherwise, the
+result is rounded to the full precision of the extended double-precision
+format.
+    The input significand must be normalized or smaller.  If the input
+significand is not normalized, `zExp' must be 0; in that case, the result
+returned is a subnormal number, and it must not require rounding.  The
+handling of underflow and overflow follows the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80
+ roundAndPackFloatx80(
+     int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+ )
+{
+    int8 roundingMode;
+    flag roundNearestEven, increment, isTiny;
+    int64 roundIncrement, roundMask, roundBits;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    if ( roundingPrecision == 80 ) goto precision80;
+    if ( roundingPrecision == 64 ) {
+        roundIncrement = LIT64( 0x0000000000000400 );
+        roundMask = LIT64( 0x00000000000007FF );
+    }
+    else if ( roundingPrecision == 32 ) {
+        roundIncrement = LIT64( 0x0000008000000000 );
+        roundMask = LIT64( 0x000000FFFFFFFFFF );
+    }
+    else {
+        goto precision80;
+    }
+    zSig0 |= ( zSig1 != 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = roundMask;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig0 & roundMask;
+    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+        if (    ( 0x7FFE < zExp )
+             || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
+           ) {
+            goto overflow;
+        }
+        if ( zExp <= 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < 0 )
+                || ( zSig0 <= zSig0 + roundIncrement );
+            shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
+            zExp = 0;
+            roundBits = zSig0 & roundMask;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+            if ( roundBits ) float_exception_flags |= float_flag_inexact;
+            zSig0 += roundIncrement;
+            if ( (sbits64) zSig0 < 0 ) zExp = 1;
+            roundIncrement = roundMask + 1;
+            if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+                roundMask |= roundIncrement;
+            }
+            zSig0 &= ~ roundMask;
+            return packFloatx80( zSign, zExp, zSig0 );
+        }
+    }
+    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    zSig0 += roundIncrement;
+    if ( zSig0 < roundIncrement ) {
+        ++zExp;
+        zSig0 = LIT64( 0x8000000000000000 );
+    }
+    roundIncrement = roundMask + 1;
+    if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+        roundMask |= roundIncrement;
+    }
+    zSig0 &= ~ roundMask;
+    if ( zSig0 == 0 ) zExp = 0;
+    return packFloatx80( zSign, zExp, zSig0 );
+ precision80:
+    increment = ( (sbits64) zSig1 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        }
+        else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && zSig1;
+            }
+            else {
+                increment = ( roundingMode == float_round_up ) && zSig1;
+            }
+        }
+    }
+    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+        if (    ( 0x7FFE < zExp )
+             || (    ( zExp == 0x7FFE )
+                  && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
+                  && increment
+                )
+           ) {
+            roundMask = 0;
+ overflow:
+            float_raise( float_flag_overflow | float_flag_inexact );
+            if (    ( roundingMode == float_round_to_zero )
+                 || ( zSign && ( roundingMode == float_round_up ) )
+                 || ( ! zSign && ( roundingMode == float_round_down ) )
+               ) {
+                return packFloatx80( zSign, 0x7FFE, ~ roundMask );
+            }
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        if ( zExp <= 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < 0 )
+                || ! increment
+                || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
+            shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
+            zExp = 0;
+            if ( isTiny && zSig1 ) float_raise( float_flag_underflow );
+            if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+            if ( roundNearestEven ) {
+                increment = ( (sbits64) zSig1 < 0 );
+            }
+            else {
+                if ( zSign ) {
+                    increment = ( roundingMode == float_round_down ) && zSig1;
+                }
+                else {
+                    increment = ( roundingMode == float_round_up ) && zSig1;
+                }
+            }
+            if ( increment ) {
+                ++zSig0;
+                zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven );
+                if ( (sbits64) zSig0 < 0 ) zExp = 1;
+            }
+            return packFloatx80( zSign, zExp, zSig0 );
+        }
+    }
+    if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+    if ( increment ) {
+        ++zSig0;
+        if ( zSig0 == 0 ) {
+            ++zExp;
+            zSig0 = LIT64( 0x8000000000000000 );
+        }
+        else {
+            zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven );
+        }
+    }
+    else {
+        if ( zSig0 == 0 ) zExp = 0;
+    }
+    
+    return packFloatx80( zSign, zExp, zSig0 );
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent
+`zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
+and returns the proper extended double-precision floating-point value
+corresponding to the abstract input.  This routine is just like
+`roundAndPackFloatx80' except that the input significand does not have to be
+normalized.
+-------------------------------------------------------------------------------
+*/
+static floatx80
+ normalizeRoundAndPackFloatx80(
+     int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+ )
+{
+    int8 shiftCount;
+
+    if ( zSig0 == 0 ) {
+        zSig0 = zSig1;
+        zSig1 = 0;
+        zExp -= 64;
+    }
+    shiftCount = countLeadingZeros64( zSig0 );
+    shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+    zExp -= shiftCount;
+    return
+        roundAndPackFloatx80( roundingPrecision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the least-significant 64 fraction bits of the quadruple-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat128Frac1( float128 a )
+{
+
+    return a.low;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the most-significant 48 fraction bits of the quadruple-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat128Frac0( float128 a )
+{
+
+    return a.high & LIT64( 0x0000FFFFFFFFFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the quadruple-precision floating-point value
+`a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int32 extractFloat128Exp( float128 a )
+{
+
+    return ( a.high>>48 ) & 0x7FFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the quadruple-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat128Sign( float128 a )
+{
+
+    return a.high>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal quadruple-precision floating-point value
+represented by the denormalized significand formed by the concatenation of
+`aSig0' and `aSig1'.  The normalized exponent is stored at the location
+pointed to by `zExpPtr'.  The most significant 49 bits of the normalized
+significand are stored at the location pointed to by `zSig0Ptr', and the
+least significant 64 bits of the normalized significand are stored at the
+location pointed to by `zSig1Ptr'.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat128Subnormal(
+     bits64 aSig0,
+     bits64 aSig1,
+     int32 *zExpPtr,
+     bits64 *zSig0Ptr,
+     bits64 *zSig1Ptr
+ )
+{
+    int8 shiftCount;
+
+    if ( aSig0 == 0 ) {
+        shiftCount = countLeadingZeros64( aSig1 ) - 15;
+        if ( shiftCount < 0 ) {
+            *zSig0Ptr = aSig1>>( - shiftCount );
+            *zSig1Ptr = aSig1<<( shiftCount & 63 );
+        }
+        else {
+            *zSig0Ptr = aSig1<<shiftCount;
+            *zSig1Ptr = 0;
+        }
+        *zExpPtr = - shiftCount - 63;
+    }
+    else {
+        shiftCount = countLeadingZeros64( aSig0 ) - 15;
+        shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
+        *zExpPtr = 1 - shiftCount;
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', the exponent `zExp', and the significand formed
+by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
+floating-point value, returning the result.  After being shifted into the
+proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
+added together to form the most significant 32 bits of the result.  This
+means that any integer portion of `zSig0' will be added into the exponent.
+Since a properly normalized significand will have an integer portion equal
+to 1, the `zExp' input should be 1 less than the desired result exponent
+whenever `zSig0' and `zSig1' concatenated form a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float128
+ packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
+{
+    float128 z;
+
+    z.low = zSig1;
+    z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and extended significand formed by the concatenation of `zSig0', `zSig1',
+and `zSig2', and returns the proper quadruple-precision floating-point value
+corresponding to the abstract input.  Ordinarily, the abstract value is
+simply rounded and packed into the quadruple-precision format, with the
+inexact exception raised if the abstract input cannot be represented
+exactly.  If the abstract value is too large, however, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned.  If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal quadruple-
+precision floating-point number.
+    The input significand must be normalized or smaller.  If the input
+significand is not normalized, `zExp' must be 0; in that case, the result
+returned is a subnormal number, and it must not require rounding.  In the
+usual case that the input significand is normalized, `zExp' must be 1 less
+than the ``true'' floating-point exponent.  The handling of underflow and
+overflow follows the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128
+ roundAndPackFloat128(
+     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
+{
+    int8 roundingMode;
+    flag roundNearestEven, increment, isTiny;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    increment = ( (sbits64) zSig2 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        }
+        else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && zSig2;
+            }
+            else {
+                increment = ( roundingMode == float_round_up ) && zSig2;
+            }
+        }
+    }
+    if ( 0x7FFD <= (bits32) zExp ) {
+        if (    ( 0x7FFD < zExp )
+             || (    ( zExp == 0x7FFD )
+                  && eq128(
+                         LIT64( 0x0001FFFFFFFFFFFF ),
+                         LIT64( 0xFFFFFFFFFFFFFFFF ),
+                         zSig0,
+                         zSig1
+                     )
+                  && increment
+                )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact );
+            if (    ( roundingMode == float_round_to_zero )
+                 || ( zSign && ( roundingMode == float_round_up ) )
+                 || ( ! zSign && ( roundingMode == float_round_down ) )
+               ) {
+                return
+                    packFloat128(
+                        zSign,
+                        0x7FFE,
+                        LIT64( 0x0000FFFFFFFFFFFF ),
+                        LIT64( 0xFFFFFFFFFFFFFFFF )
+                    );
+            }
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        if ( zExp < 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ! increment
+                || lt128(
+                       zSig0,
+                       zSig1,
+                       LIT64( 0x0001FFFFFFFFFFFF ),
+                       LIT64( 0xFFFFFFFFFFFFFFFF )
+                   );
+            shift128ExtraRightJamming(
+                zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
+            zExp = 0;
+            if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
+            if ( roundNearestEven ) {
+                increment = ( (sbits64) zSig2 < 0 );
+            }
+            else {
+                if ( zSign ) {
+                    increment = ( roundingMode == float_round_down ) && zSig2;
+                }
+                else {
+                    increment = ( roundingMode == float_round_up ) && zSig2;
+                }
+            }
+        }
+    }
+    if ( zSig2 ) float_exception_flags |= float_flag_inexact;
+    if ( increment ) {
+        add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
+        zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
+    }
+    else {
+        if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
+    }
+    return packFloat128( zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand formed by the concatenation of `zSig0' and `zSig1', and
+returns the proper quadruple-precision floating-point value corresponding to
+the abstract input.  This routine is just like `roundAndPackFloat128' except
+that the input significand has fewer bits and does not have to be normalized
+in any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float128
+ normalizeRoundAndPackFloat128(
+     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
+{
+    int8 shiftCount;
+    bits64 zSig2;
+
+    if ( zSig0 == 0 ) {
+        zSig0 = zSig1;
+        zSig1 = 0;
+        zExp -= 64;
+    }
+    shiftCount = countLeadingZeros64( zSig0 ) - 15;
+    if ( 0 <= shiftCount ) {
+        zSig2 = 0;
+        shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+    }
+    else {
+        shift128ExtraRightJamming(
+            zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
+    }
+    zExp -= shiftCount;
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the single-precision floating-point format.  The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int32 a )
+{
+    flag zSign;
+
+    if ( a == 0 ) return 0;
+    if ( a == 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+    zSign = ( a < 0 );
+    return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the double-precision floating-point format.  The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 int32_to_float64( int32 a )
+{
+    flag aSign;
+    uint32 absA;
+    int8 shiftCount;
+    bits64 zSig;
+
+    if ( a == 0 ) return 0;
+    aSign = ( a < 0 );
+    absA = aSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 21;
+    zSig = absA;
+    return packFloat64( aSign, 0x432 - shiftCount, zSig<<shiftCount );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a'
+to the extended double-precision floating-point format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 int32_to_floatx80( int32 a )
+{
+    flag zSign;
+    uint32 absA;
+    int8 shiftCount;
+    bits64 zSig;
+
+    if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 32;
+    zSig = absA;
+    return packFloatx80( zSign, 0x403E - shiftCount, zSig<<shiftCount );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the quadruple-precision floating-point format.  The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 int32_to_float128( int32 a )
+{
+    flag zSign;
+    uint32 absA;
+    int8 shiftCount;
+    bits64 zSig0;
+
+    if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+    zSign = ( a < 0 );
+    absA = zSign ? - a : a;
+    shiftCount = countLeadingZeros32( absA ) + 17;
+    zSig0 = absA;
+    return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode.  If `a' is a NaN, the largest
+positive integer is returned.  Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32( float32 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits32 aSig;
+    bits64 zSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+    if ( aExp ) aSig |= 0x00800000;
+    shiftCount = 0xAF - aExp;
+    zSig = aSig;
+    zSig <<= 32;
+    if ( 0 < shiftCount ) shift64RightJamming( zSig, shiftCount, &zSig );
+    return roundAndPackInt32( aSign, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero.  If
+`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32_round_to_zero( float32 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits32 aSig;
+    int32 z;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x9E;
+    if ( 0 <= shiftCount ) {
+        if ( a == 0xCF000000 ) return 0x80000000;
+        float_raise( float_flag_invalid );
+        if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+        return 0x80000000;
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    aSig = ( aSig | 0x00800000 )<<8;
+    z = aSig>>( - shiftCount );
+    if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return aSign ? - z : z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float32_to_float64( float32 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits32 aSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the extended double-precision floating-point format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float32_to_floatx80( float32 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits32 aSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) );
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    aSig |= 0x00800000;
+    return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float32_to_float128( float32 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits32 aSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
+        return packFloat128( aSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the single-precision floating-point value `a' to an integer, and
+returns the result as a single-precision floating-point value.  The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits32 lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    float32 z;
+
+    aExp = extractFloat32Exp( a );
+    if ( 0x96 <= aExp ) {
+        if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+            return propagateFloat32NaN( a, a );
+        }
+        return a;
+    }
+    if ( aExp <= 0x7E ) {
+        if ( (bits32) ( a<<1 ) == 0 ) return a;
+        float_exception_flags |= float_flag_inexact;
+        aSign = extractFloat32Sign( a );
+        switch ( float_rounding_mode ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+                return packFloat32( aSign, 0x7F, 0 );
+            }
+            break;
+         case float_round_down:
+            return aSign ? 0xBF800000 : 0;
+         case float_round_up:
+            return aSign ? 0x80000000 : 0x3F800000;
+        }
+        return packFloat32( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x96 - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = a;
+    roundingMode = float_rounding_mode;
+    if ( roundingMode == float_round_nearest_even ) {
+        z += lastBitMask>>1;
+        if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+            z += roundBitsMask;
+        }
+    }
+    z &= ~ roundBitsMask;
+    if ( z != a ) float_exception_flags |= float_flag_inexact;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the single-precision
+floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
+before being returned.  `zSign' is ignored if the result is a NaN.  The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 6;
+    bSig <<= 6;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0xFF ) {
+            if ( aSig ) return propagateFloat32NaN( a, b );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig |= 0x20000000;
+        }
+        shift32RightJamming( bSig, expDiff, &bSig );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b );
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig |= 0x20000000;
+        }
+        shift32RightJamming( aSig, - expDiff, &aSig );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0xFF ) {
+            if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+            return a;
+        }
+        if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+        zSig = 0x40000000 + aSig + bSig;
+        zExp = aExp;
+        goto roundAndPack;
+    }
+    aSig |= 0x20000000;
+    zSig = ( aSig + bSig )<<1;
+    --zExp;
+    if ( (sbits32) zSig < 0 ) {
+        zSig = aSig + bSig;
+        ++zExp;
+    }
+ roundAndPack:
+    return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the single-
+precision floating-point values `a' and `b'.  If `zSign' is true, the
+difference is negated before being returned.  `zSign' is ignored if the
+result is a NaN.  The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 7;
+    bSig <<= 7;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0xFF ) {
+        if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return packFloat32( zSign ^ 1, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig |= 0x40000000;
+    }
+    shift32RightJamming( aSig, - expDiff, &aSig );
+    bSig |= 0x40000000;
+ bBigger:
+    zSig = bSig - aSig;
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig |= 0x40000000;
+    }
+    shift32RightJamming( bSig, expDiff, &bSig );
+    aSig |= 0x40000000;
+ aBigger:
+    zSig = aSig - bSig;
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the single-precision floating-point values `a'
+and `b'.  The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_add( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat32Sigs( a, b, aSign );
+    }
+    else {
+        return subFloat32Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the single-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sub( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat32Sigs( a, b, aSign );
+    }
+    else {
+        return addFloat32Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the single-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_mul( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig;
+    bits64 zSig64;
+    bits32 zSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b );
+        }
+        if ( ( bExp | bSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        if ( ( aExp | aSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x7F;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 );
+    zSig = zSig64;
+    if ( 0 <= (sbits32) ( zSig<<1 ) ) {
+        zSig <<= 1;
+        --zExp;
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the single-precision floating-point value `a'
+by the corresponding value `b'.  The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_div( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b );
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b );
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return packFloat32( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+                float_raise( float_flag_invalid );
+                return float32_default_nan;
+            }
+            float_raise( float_flag_divbyzero );
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x7D;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    if ( bSig <= ( aSig + aSig ) ) {
+        aSig >>= 1;
+        ++zExp;
+    }
+    zSig = ( ( (bits64) aSig )<<32 ) / bSig;
+    if ( ( zSig & 0x3F ) == 0 ) {
+        zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 );
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the single-precision floating-point value `a'
+with respect to the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_rem( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, expDiff;
+    bits32 aSig, bSig;
+    bits32 q;
+    bits64 aSig64, bSig64, q64;
+    bits32 alternateASig;
+    sbits32 sigMean;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b );
+        }
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return a;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    expDiff = aExp - bExp;
+    aSig |= 0x00800000;
+    bSig |= 0x00800000;
+    if ( expDiff < 32 ) {
+        aSig <<= 8;
+        bSig <<= 8;
+        if ( expDiff < 0 ) {
+            if ( expDiff < -1 ) return a;
+            aSig >>= 1;
+        }
+        q = ( bSig <= aSig );
+        if ( q ) aSig -= bSig;
+        if ( 0 < expDiff ) {
+            q = ( ( (bits64) aSig )<<32 ) / bSig;
+            q >>= 32 - expDiff;
+            bSig >>= 2;
+            aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+        }
+        else {
+            aSig >>= 2;
+            bSig >>= 2;
+        }
+    }
+    else {
+        if ( bSig <= aSig ) aSig -= bSig;
+        aSig64 = ( (bits64) aSig )<<40;
+        bSig64 = ( (bits64) bSig )<<40;
+        expDiff -= 64;
+        while ( 0 < expDiff ) {
+            q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+            q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+            aSig64 = - ( ( bSig * q64 )<<38 );
+            expDiff -= 62;
+        }
+        expDiff += 64;
+        q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+        q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+        q = q64>>( 64 - expDiff );
+        bSig <<= 6;
+        aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q;
+    }
+    do {
+        alternateASig = aSig;
+        ++q;
+        aSig -= bSig;
+    } while ( 0 <= (sbits32) aSig );
+    sigMean = aSig + alternateASig;
+    if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+        aSig = alternateASig;
+    }
+    zSign = ( (sbits32) aSig < 0 );
+    if ( zSign ) aSig = - aSig;
+    return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the single-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sqrt( float32 a )
+{
+    flag aSign;
+    int16 aExp, zExp;
+    bits32 aSig, zSig;
+    bits64 rem, term;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, 0 );
+        if ( ! aSign ) return a;
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig ) == 0 ) return a;
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return 0;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+    aSig = ( aSig | 0x00800000 )<<8;
+    zSig = estimateSqrt32( aExp, aSig ) + 2;
+    if ( ( zSig & 0x7F ) <= 5 ) {
+        if ( zSig < 2 ) {
+            zSig = 0xFFFFFFFF;
+        }
+        else {
+            aSig >>= aExp & 1;
+            term = ( (bits64) zSig ) * zSig;
+            rem = ( ( (bits64) aSig )<<32 ) - term;
+            while ( (sbits64) rem < 0 ) {
+                --zSig;
+                rem += ( ( (bits64) zSig )<<1 ) | 1;
+            }
+            zSig |= ( rem != 0 );
+        }
+    }
+    shift32RightJamming( zSig, 1, &zSig );
+    return roundAndPackFloat32( 0, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq( float32 a, float32 b )
+{
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The invalid exception is raised
+if either operand is a NaN.  Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq_signaling( float32 a, float32 b )
+{
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+cause an exception.  Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le_quiet( float32 a, float32 b )
+{
+    flag aSign, bSign;
+    //int16 aExp, bExp;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt_quiet( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode.  If `a' is a NaN, the largest
+positive integer is returned.  Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32( float64 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits64 aSig;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x42C - aExp;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
+    return roundAndPackInt32( aSign, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero.  If
+`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32_round_to_zero( float64 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits64 aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    shiftCount = 0x433 - aExp;
+    if ( shiftCount < 21 ) {
+        if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+        goto invalid;
+    }
+    else if ( 52 < shiftCount ) {
+        if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    aSig |= LIT64( 0x0010000000000000 );
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_exception_flags |= float_flag_invalid;
+        return aSign ? 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement unsigned integer format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode.  If `a' is a NaN, the largest
+positive integer is returned.  Otherwise, if the conversion overflows, the
+largest positive integer is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_uint32( float64 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits64 aSig;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = 0; //extractFloat64Sign( a );
+    //if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x42C - aExp;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
+    return roundAndPackInt32( aSign, aSig );
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero.  If
+`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+conversion overflows, the largest positive integer is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_uint32_round_to_zero( float64 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits64 aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    shiftCount = 0x433 - aExp;
+    if ( shiftCount < 21 ) {
+        if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+        goto invalid;
+    }
+    else if ( 52 < shiftCount ) {
+        if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    aSig |= LIT64( 0x0010000000000000 );
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_exception_flags |= float_flag_invalid;
+        return aSign ? 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return z;
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the single-precision floating-point format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float64_to_float32( float64 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits64 aSig;
+    bits32 zSig;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a ) );
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    shift64RightJamming( aSig, 22, &aSig );
+    zSig = aSig;
+    if ( aExp || zSig ) {
+        zSig |= 0x40000000;
+        aExp -= 0x381;
+    }
+    return roundAndPackFloat32( aSign, aExp, zSig );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the extended double-precision floating-point format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float64_to_floatx80( float64 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits64 aSig;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a ) );
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    return
+        packFloatx80(
+            aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the quadruple-precision floating-point format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float64_to_float128( float64 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits64 aSig, zSig0, zSig1;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) );
+        return packFloat128( aSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+        --aExp;
+    }
+    shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
+    return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the double-precision floating-point value `a' to an integer, and
+returns the result as a double-precision floating-point value.  The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits64 lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    float64 z;
+
+    aExp = extractFloat64Exp( a );
+    if ( 0x433 <= aExp ) {
+        if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) {
+            return propagateFloat64NaN( a, a );
+        }
+        return a;
+    }
+    if ( aExp <= 0x3FE ) {
+        if ( (bits64) ( a<<1 ) == 0 ) return a;
+        float_exception_flags |= float_flag_inexact;
+        aSign = extractFloat64Sign( a );
+        switch ( float_rounding_mode ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) {
+                return packFloat64( aSign, 0x3FF, 0 );
+            }
+            break;
+         case float_round_down:
+            return aSign ? LIT64( 0xBFF0000000000000 ) : 0;
+         case float_round_up:
+            return
+            aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 );
+        }
+        return packFloat64( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x433 - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = a;
+    roundingMode = float_rounding_mode;
+    if ( roundingMode == float_round_nearest_even ) {
+        z += lastBitMask>>1;
+        if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+            z += roundBitsMask;
+        }
+    }
+    z &= ~ roundBitsMask;
+    if ( z != a ) float_exception_flags |= float_flag_inexact;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the double-precision
+floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
+before being returned.  `zSign' is ignored if the result is a NaN.  The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 9;
+    bSig <<= 9;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FF ) {
+            if ( aSig ) return propagateFloat64NaN( a, b );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig |= LIT64( 0x2000000000000000 );
+        }
+        shift64RightJamming( bSig, expDiff, &bSig );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FF ) {
+            if ( bSig ) return propagateFloat64NaN( a, b );
+            return packFloat64( zSign, 0x7FF, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig |= LIT64( 0x2000000000000000 );
+        }
+        shift64RightJamming( aSig, - expDiff, &aSig );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FF ) {
+            if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+            return a;
+        }
+        if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+        zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
+        zExp = aExp;
+        goto roundAndPack;
+    }
+    aSig |= LIT64( 0x2000000000000000 );
+    zSig = ( aSig + bSig )<<1;
+    --zExp;
+    if ( (sbits64) zSig < 0 ) {
+        zSig = aSig + bSig;
+        ++zExp;
+    }
+ roundAndPack:
+    return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the double-
+precision floating-point values `a' and `b'.  If `zSign' is true, the
+difference is negated before being returned.  `zSign' is ignored if the
+result is a NaN.  The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 10;
+    bSig <<= 10;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FF ) {
+        if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+        float_raise( float_flag_invalid );
+        return float64_default_nan;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloat64( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b );
+        return packFloat64( zSign ^ 1, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig |= LIT64( 0x4000000000000000 );
+    }
+    shift64RightJamming( aSig, - expDiff, &aSig );
+    bSig |= LIT64( 0x4000000000000000 );
+ bBigger:
+    zSig = bSig - aSig;
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig |= LIT64( 0x4000000000000000 );
+    }
+    shift64RightJamming( bSig, expDiff, &bSig );
+    aSig |= LIT64( 0x4000000000000000 );
+ aBigger:
+    zSig = aSig - bSig;
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the double-precision floating-point values `a'
+and `b'.  The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_add( float64 a, float64 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat64Sigs( a, b, aSign );
+    }
+    else {
+        return subFloat64Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the double-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sub( float64 a, float64 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat64Sigs( a, b, aSign );
+    }
+    else {
+        return addFloat64Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the double-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_mul( float64 a, float64 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig0, zSig1;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    bSign = extractFloat64Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FF ) {
+        if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+            return propagateFloat64NaN( a, b );
+        }
+        if ( ( bExp | bSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b );
+        if ( ( aExp | aSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x3FF;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    mul64To128( aSig, bSig, &zSig0, &zSig1 );
+    zSig0 |= ( zSig1 != 0 );
+    if ( 0 <= (sbits64) ( zSig0<<1 ) ) {
+        zSig0 <<= 1;
+        --zExp;
+    }
+    return roundAndPackFloat64( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the double-precision floating-point value `a'
+by the corresponding value `b'.  The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_div( float64 a, float64 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig;
+    bits64 rem0, rem1;
+    bits64 term0, term1;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    bSign = extractFloat64Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, b );
+        if ( bExp == 0x7FF ) {
+            if ( bSig ) return propagateFloat64NaN( a, b );
+            float_raise( float_flag_invalid );
+            return float64_default_nan;
+        }
+        return packFloat64( zSign, 0x7FF, 0 );
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b );
+        return packFloat64( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+                float_raise( float_flag_invalid );
+                return float64_default_nan;
+            }
+            float_raise( float_flag_divbyzero );
+            return packFloat64( zSign, 0x7FF, 0 );
+        }
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x3FD;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    if ( bSig <= ( aSig + aSig ) ) {
+        aSig >>= 1;
+        ++zExp;
+    }
+    zSig = estimateDiv128To64( aSig, 0, bSig );
+    if ( ( zSig & 0x1FF ) <= 2 ) {
+        mul64To128( bSig, zSig, &term0, &term1 );
+        sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+        while ( (sbits64) rem0 < 0 ) {
+            --zSig;
+            add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+        }
+        zSig |= ( rem1 != 0 );
+    }
+    return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the double-precision floating-point value `a'
+with respect to the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_rem( float64 a, float64 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, expDiff;
+    bits64 aSig, bSig;
+    bits64 q, alternateASig;
+    sbits64 sigMean;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    bSig = extractFloat64Frac( b );
+    bExp = extractFloat64Exp( b );
+    bSign = extractFloat64Sign( b );
+    if ( aExp == 0x7FF ) {
+        if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+            return propagateFloat64NaN( a, b );
+        }
+        float_raise( float_flag_invalid );
+        return float64_default_nan;
+    }
+    if ( bExp == 0x7FF ) {
+        if ( bSig ) return propagateFloat64NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            float_raise( float_flag_invalid );
+            return float64_default_nan;
+        }
+        normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return a;
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    expDiff = aExp - bExp;
+    aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11;
+    bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+    if ( expDiff < 0 ) {
+        if ( expDiff < -1 ) return a;
+        aSig >>= 1;
+    }
+    q = ( bSig <= aSig );
+    if ( q ) aSig -= bSig;
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        aSig = - ( ( bSig>>2 ) * q );
+        expDiff -= 62;
+    }
+    expDiff += 64;
+    if ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        q >>= 64 - expDiff;
+        bSig >>= 2;
+        aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+    }
+    else {
+        aSig >>= 2;
+        bSig >>= 2;
+    }
+    do {
+        alternateASig = aSig;
+        ++q;
+        aSig -= bSig;
+    } while ( 0 <= (sbits64) aSig );
+    sigMean = aSig + alternateASig;
+    if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+        aSig = alternateASig;
+    }
+    zSign = ( (sbits64) aSig < 0 );
+    if ( zSign ) aSig = - aSig;
+    return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the double-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sqrt( float64 a )
+{
+    flag aSign;
+    int16 aExp, zExp;
+    bits64 aSig, zSig;
+    bits64 rem0, rem1, term0, term1; //, shiftedRem;
+    //float64 z;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, a );
+        if ( ! aSign ) return a;
+        float_raise( float_flag_invalid );
+        return float64_default_nan;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig ) == 0 ) return a;
+        float_raise( float_flag_invalid );
+        return float64_default_nan;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return 0;
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
+    aSig |= LIT64( 0x0010000000000000 );
+    zSig = estimateSqrt32( aExp, aSig>>21 );
+    zSig <<= 31;
+    aSig <<= 9 - ( aExp & 1 );
+    zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2;
+    if ( ( zSig & 0x3FF ) <= 5 ) {
+        if ( zSig < 2 ) {
+            zSig = LIT64( 0xFFFFFFFFFFFFFFFF );
+        }
+        else {
+            aSig <<= 2;
+            mul64To128( zSig, zSig, &term0, &term1 );
+            sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+            while ( (sbits64) rem0 < 0 ) {
+                --zSig;
+                shortShift128Left( 0, zSig, 1, &term0, &term1 );
+                term1 |= 1;
+                add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+            }
+            zSig |= ( ( rem0 | rem1 ) != 0 );
+        }
+    }
+    shift64RightJamming( zSig, 1, &zSig );
+    return roundAndPackFloat64( 0, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq( float64 a, float64 b )
+{
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le( float64 a, float64 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt( float64 a, float64 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The invalid exception is raised
+if either operand is a NaN.  Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq_signaling( float64 a, float64 b )
+{
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+cause an exception.  Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le_quiet( float64 a, float64 b )
+{
+    flag aSign, bSign;
+    //int16 aExp, bExp;
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt_quiet( float64 a, float64 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+       ) {
+        if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat64Sign( a );
+    bSign = extractFloat64Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic---which means in particular that the conversion
+is rounded according to the current rounding mode.  If `a' is a NaN, the
+largest positive integer is returned.  Otherwise, if the conversion
+overflows, the largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32( floatx80 a )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    bits64 aSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+    shiftCount = 0x4037 - aExp;
+    if ( shiftCount <= 0 ) shiftCount = 1;
+    shift64RightJamming( aSig, shiftCount, &aSig );
+    return roundAndPackInt32( aSign, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic, except that the conversion is always rounded
+toward zero.  If `a' is a NaN, the largest positive integer is returned.
+Otherwise, if the conversion overflows, the largest integer with the same
+sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32_round_to_zero( floatx80 a )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    bits64 aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    shiftCount = 0x403E - aExp;
+    if ( shiftCount < 32 ) {
+        if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+        goto invalid;
+    }
+    else if ( 63 < shiftCount ) {
+        if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_exception_flags |= float_flag_invalid;
+        return aSign ? 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the single-precision floating-point format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 floatx80_to_float32( floatx80 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 aSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( aSig<<1 ) ) {
+            return commonNaNToFloat32( floatx80ToCommonNaN( a ) );
+        }
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    shift64RightJamming( aSig, 33, &aSig );
+    if ( aExp || aSig ) aExp -= 0x3F81;
+    return roundAndPackFloat32( aSign, aExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the double-precision floating-point format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 floatx80_to_float64( floatx80 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 aSig, zSig;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( aSig<<1 ) ) {
+            return commonNaNToFloat64( floatx80ToCommonNaN( a ) );
+        }
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    shift64RightJamming( aSig, 1, &zSig );
+    if ( aExp || aSig ) aExp -= 0x3C01;
+    return roundAndPackFloat64( aSign, aExp, zSig );
+
+}
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the quadruple-precision floating-point format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 floatx80_to_float128( floatx80 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits64 aSig, zSig0, zSig1;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
+        return commonNaNToFloat128( floatx80ToCommonNaN( a ) );
+    }
+    shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
+    return packFloat128( aSign, aExp, zSig0, zSig1 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the extended double-precision floating-point value `a' to an integer,
+and returns the result as an extended quadruple-precision floating-point
+value.  The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    floatx80 z;
+
+    aExp = extractFloatx80Exp( a );
+    if ( 0x403E <= aExp ) {
+        if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) {
+            return propagateFloatx80NaN( a, a );
+        }
+        return a;
+    }
+    if ( aExp <= 0x3FFE ) {
+        if (    ( aExp == 0 )
+             && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
+            return a;
+        }
+        float_exception_flags |= float_flag_inexact;
+        aSign = extractFloatx80Sign( a );
+        switch ( float_rounding_mode ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 )
+               ) {
+                return
+                    packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
+            }
+            break;
+         case float_round_down:
+            return
+                  aSign ?
+                      packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) )
+                : packFloatx80( 0, 0, 0 );
+         case float_round_up:
+            return
+                  aSign ? packFloatx80( 1, 0, 0 )
+                : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) );
+        }
+        return packFloatx80( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x403E - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = a;
+    roundingMode = float_rounding_mode;
+    if ( roundingMode == float_round_nearest_even ) {
+        z.low += lastBitMask>>1;
+        if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+            z.low += roundBitsMask;
+        }
+    }
+    z.low &= ~ roundBitsMask;
+    if ( z.low == 0 ) {
+        ++z.high;
+        z.low = LIT64( 0x8000000000000000 );
+    }
+    if ( z.low != a.low ) float_exception_flags |= float_flag_inexact;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the extended double-
+precision floating-point values `a' and `b'.  If `zSign' is true, the sum is
+negated before being returned.  `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+    int32 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig0, zSig1;
+    int32 expDiff;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FFF ) {
+            if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+            return a;
+        }
+        if ( bExp == 0 ) --expDiff;
+        shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FFF ) {
+            if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        if ( aExp == 0 ) ++expDiff;
+        shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FFF ) {
+            if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+                return propagateFloatx80NaN( a, b );
+            }
+            return a;
+        }
+        zSig1 = 0;
+        zSig0 = aSig + bSig;
+        if ( aExp == 0 ) {
+            normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 );
+            goto roundAndPack;
+        }
+        zExp = aExp;
+        goto shiftRight1;
+    }
+    
+    zSig0 = aSig + bSig;
+
+    if ( (sbits64) zSig0 < 0 ) goto roundAndPack; 
+ shiftRight1:
+    shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
+    zSig0 |= LIT64( 0x8000000000000000 );
+    ++zExp;
+ roundAndPack:
+    return
+        roundAndPackFloatx80(
+            floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the extended
+double-precision floating-point values `a' and `b'.  If `zSign' is true,
+the difference is negated before being returned.  `zSign' is ignored if the
+result is a NaN.  The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+    int32 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig0, zSig1;
+    int32 expDiff;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+            return propagateFloatx80NaN( a, b );
+        }
+        float_raise( float_flag_invalid );
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    zSig1 = 0;
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloatx80( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FFF ) {
+        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) ++expDiff;
+    shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ bBigger:
+    sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 );
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) --expDiff;
+    shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ aBigger:
+    sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 );
+    zExp = aExp;
+ normalizeRoundAndPack:
+    return
+        normalizeRoundAndPackFloatx80(
+            floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the extended double-precision floating-point
+values `a' and `b'.  The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_add( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+    
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign == bSign ) {
+        return addFloatx80Sigs( a, b, aSign );
+    }
+    else {
+        return subFloatx80Sigs( a, b, aSign );
+    }
+    
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the extended double-precision floating-
+point values `a' and `b'.  The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sub( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign == bSign ) {
+        return subFloatx80Sigs( a, b, aSign );
+    }
+    else {
+        return addFloatx80Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the extended double-precision floating-
+point values `a' and `b'.  The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_mul( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig0, zSig1;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    bSign = extractFloatx80Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if (    (bits64) ( aSig<<1 )
+             || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+            return propagateFloatx80NaN( a, b );
+        }
+        if ( ( bExp | bSig ) == 0 ) goto invalid;
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid );
+            z.low = floatx80_default_nan_low;
+            z.high = floatx80_default_nan_high;
+            return z;
+        }
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x3FFE;
+    mul64To128( aSig, bSig, &zSig0, &zSig1 );
+    if ( 0 < (sbits64) zSig0 ) {
+        shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
+        --zExp;
+    }
+    return
+        roundAndPackFloatx80(
+            floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the extended double-precision floating-point
+value `a' by the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_div( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    bits64 aSig, bSig, zSig0, zSig1;
+    bits64 rem0, rem1, rem2, term0, term1, term2;
+    floatx80 z;
+
+    aSig = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    bSign = extractFloatx80Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        if ( bExp == 0x7FFF ) {
+            if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+            goto invalid;
+        }
+        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        return packFloatx80( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+                float_raise( float_flag_invalid );
+                z.low = floatx80_default_nan_low;
+                z.high = floatx80_default_nan_high;
+                return z;
+            }
+            float_raise( float_flag_divbyzero );
+            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        }
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+        normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x3FFE;
+    rem1 = 0;
+    if ( bSig <= aSig ) {
+        shift128Right( aSig, 0, 1, &aSig, &rem1 );
+        ++zExp;
+    }
+    zSig0 = estimateDiv128To64( aSig, rem1, bSig );
+    mul64To128( bSig, zSig0, &term0, &term1 );
+    sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
+    while ( (sbits64) rem0 < 0 ) {
+        --zSig0;
+        add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+    }
+    zSig1 = estimateDiv128To64( rem1, 0, bSig );
+    if ( (bits64) ( zSig1<<1 ) <= 8 ) {
+        mul64To128( bSig, zSig1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        while ( (sbits64) rem1 < 0 ) {
+            --zSig1;
+            add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
+        }
+        zSig1 |= ( ( rem1 | rem2 ) != 0 );
+    }
+    return
+        roundAndPackFloatx80(
+            floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the extended double-precision floating-point value
+`a' with respect to the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_rem( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, expDiff;
+    bits64 aSig0, aSig1, bSig;
+    bits64 q, term0, term1, alternateASig0, alternateASig1;
+    floatx80 z;
+
+    aSig0 = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    bSig = extractFloatx80Frac( b );
+    bExp = extractFloatx80Exp( b );
+    bSign = extractFloatx80Sign( b );
+    if ( aExp == 0x7FFF ) {
+        if (    (bits64) ( aSig0<<1 )
+             || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+            return propagateFloatx80NaN( a, b );
+        }
+        goto invalid;
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid );
+            z.low = floatx80_default_nan_low;
+            z.high = floatx80_default_nan_high;
+            return z;
+        }
+        normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( (bits64) ( aSig0<<1 ) == 0 ) return a;
+        normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+    }
+    bSig |= LIT64( 0x8000000000000000 );
+    zSign = aSign;
+    expDiff = aExp - bExp;
+    aSig1 = 0;
+    if ( expDiff < 0 ) {
+        if ( expDiff < -1 ) return a;
+        shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
+        expDiff = 0;
+    }
+    q = ( bSig <= aSig0 );
+    if ( q ) aSig0 -= bSig;
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        mul64To128( bSig, q, &term0, &term1 );
+        sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 );
+        expDiff -= 62;
+    }
+    expDiff += 64;
+    if ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        q >>= 64 - expDiff;
+        mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 );
+        sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 );
+        while ( le128( term0, term1, aSig0, aSig1 ) ) {
+            ++q;
+            sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+        }
+    }
+    else {
+        term1 = 0;
+        term0 = bSig;
+    }
+    sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
+    if (    lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
+         || (    eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
+              && ( q & 1 ) )
+       ) {
+        aSig0 = alternateASig0;
+        aSig1 = alternateASig1;
+        zSign = ! zSign;
+    }
+    return
+        normalizeRoundAndPackFloatx80(
+            80, zSign, bExp + expDiff, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the extended double-precision floating-point
+value `a'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sqrt( floatx80 a )
+{
+    flag aSign;
+    int32 aExp, zExp;
+    bits64 aSig0, aSig1, zSig0, zSig1;
+    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    bits64 shiftedRem0, shiftedRem1;
+    floatx80 z;
+
+    aSig0 = extractFloatx80Frac( a );
+    aExp = extractFloatx80Exp( a );
+    aSign = extractFloatx80Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a );
+        if ( ! aSign ) return a;
+        goto invalid;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig0 ) == 0 ) return a;
+ invalid:
+        float_raise( float_flag_invalid );
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
+        normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+    }
+    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF;
+    zSig0 = estimateSqrt32( aExp, aSig0>>32 );
+    zSig0 <<= 31;
+    aSig1 = 0;
+    shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 );
+    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
+    if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
+    shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
+    mul64To128( zSig0, zSig0, &term0, &term1 );
+    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+    while ( (sbits64) rem0 < 0 ) {
+        --zSig0;
+        shortShift128Left( 0, zSig0, 1, &term0, &term1 );
+        term1 |= 1;
+        add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+    }
+    shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
+    zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
+    if ( (bits64) ( zSig1<<1 ) <= 10 ) {
+        if ( zSig1 == 0 ) zSig1 = 1;
+        mul64To128( zSig0, zSig1, &term1, &term2 );
+        shortShift128Left( term1, term2, 1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        mul64To128( zSig1, zSig1, &term2, &term3 );
+        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (sbits64) rem1 < 0 ) {
+            --zSig1;
+            shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
+            term3 |= 1;
+            add192(
+                rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    return
+        roundAndPackFloatx80(
+            floatx80_rounding_precision, 0, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+equal to the corresponding value `b', and 0 otherwise.  The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq( floatx80 a, floatx80 b )
+{
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than or equal to the corresponding value `b', and 0 otherwise.  The
+comparison is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than the corresponding value `b', and 0 otherwise.  The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is equal
+to the corresponding value `b', and 0 otherwise.  The invalid exception is
+raised if either operand is a NaN.  Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq_signaling( floatx80 a, floatx80 b )
+{
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs
+do not cause an exception.  Otherwise, the comparison is performed according
+to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le_quiet( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause
+an exception.  Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt_quiet( floatx80 a, floatx80 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+       ) {
+        if (    floatx80_is_signaling_nan( a )
+             || floatx80_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloatx80Sign( a );
+    bSign = extractFloatx80Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode.  If `a' is a NaN, the largest
+positive integer is returned.  Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32( float128 a )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    bits64 aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+    aSig0 |= ( aSig1 != 0 );
+    shiftCount = 0x4028 - aExp;
+    if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
+    return roundAndPackInt32( aSign, aSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero.  If
+`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32_round_to_zero( float128 a )
+{
+    flag aSign;
+    int32 aExp, shiftCount;
+    bits64 aSig0, aSig1, savedASig;
+    int32 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    aSig0 |= ( aSig1 != 0 );
+    shiftCount = 0x402F - aExp;
+    if ( shiftCount < 17 ) {
+        if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
+        goto invalid;
+    }
+    else if ( 48 < shiftCount ) {
+        if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    aSig0 |= LIT64( 0x0001000000000000 );
+    savedASig = aSig0;
+    aSig0 >>= shiftCount;
+    z = aSig0;
+    if ( aSign ) z = - z;
+    if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+        float_exception_flags |= float_flag_invalid;
+        return aSign ? 0x80000000 : 0x7FFFFFFF;
+    }
+    if ( ( aSig0<<shiftCount ) != savedASig ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the single-precision floating-point format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float128_to_float32( float128 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 aSig0, aSig1;
+    bits32 zSig;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloat32( float128ToCommonNaN( a ) );
+        }
+        return packFloat32( aSign, 0xFF, 0 );
+    }
+    aSig0 |= ( aSig1 != 0 );
+    shift64RightJamming( aSig0, 18, &aSig0 );
+    zSig = aSig0;
+    if ( aExp || zSig ) {
+        zSig |= 0x40000000;
+        aExp -= 0x3F81;
+    }
+    return roundAndPackFloat32( aSign, aExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the double-precision floating-point format.  The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float128_to_float64( float128 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloat64( float128ToCommonNaN( a ) );
+        }
+        return packFloat64( aSign, 0x7FF, 0 );
+    }
+    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+    aSig0 |= ( aSig1 != 0 );
+    if ( aExp || aSig0 ) {
+        aSig0 |= LIT64( 0x4000000000000000 );
+        aExp -= 0x3C01;
+    }
+    return roundAndPackFloat64( aSign, aExp, aSig0 );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the extended double-precision floating-point format.  The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float128_to_floatx80( float128 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 aSig0, aSig1;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) {
+            return commonNaNToFloatx80( float128ToCommonNaN( a ) );
+        }
+        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    else {
+        aSig0 |= LIT64( 0x0001000000000000 );
+    }
+    shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
+    return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the quadruple-precision floating-point value `a' to an integer, and
+returns the result as a quadruple-precision floating-point value.  The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 a )
+{
+    flag aSign;
+    int32 aExp;
+    bits64 lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    float128 z;
+
+    aExp = extractFloat128Exp( a );
+    if ( 0x402F <= aExp ) {
+        if ( 0x406F <= aExp ) {
+            if (    ( aExp == 0x7FFF )
+                 && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
+               ) {
+                return propagateFloat128NaN( a, a );
+            }
+            return a;
+        }
+        lastBitMask = 1;
+        lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
+        roundBitsMask = lastBitMask - 1;
+        z = a;
+        roundingMode = float_rounding_mode;
+        if ( roundingMode == float_round_nearest_even ) {
+            if ( lastBitMask ) {
+                add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
+                if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+            }
+            else {
+                if ( (sbits64) z.low < 0 ) {
+                    ++z.high;
+                    if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
+                }
+            }
+        }
+        else if ( roundingMode != float_round_to_zero ) {
+            if (   extractFloat128Sign( z )
+                 ^ ( roundingMode == float_round_up ) ) {
+                add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
+            }
+        }
+        z.low &= ~ roundBitsMask;
+    }
+    else {
+        if ( aExp <= 0x3FFE ) {
+            if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+            float_exception_flags |= float_flag_inexact;
+            aSign = extractFloat128Sign( a );
+            switch ( float_rounding_mode ) {
+             case float_round_nearest_even:
+                if (    ( aExp == 0x3FFE )
+                     && (   extractFloat128Frac0( a )
+                          | extractFloat128Frac1( a ) )
+                   ) {
+                    return packFloat128( aSign, 0x3FFF, 0, 0 );
+                }
+                break;
+             case float_round_down:
+                return
+                      aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
+                    : packFloat128( 0, 0, 0, 0 );
+             case float_round_up:
+                return
+                      aSign ? packFloat128( 1, 0, 0, 0 )
+                    : packFloat128( 0, 0x3FFF, 0, 0 );
+            }
+            return packFloat128( aSign, 0, 0, 0 );
+        }
+        lastBitMask = 1;
+        lastBitMask <<= 0x402F - aExp;
+        roundBitsMask = lastBitMask - 1;
+        z.low = 0;
+        z.high = a.high;
+        roundingMode = float_rounding_mode;
+        if ( roundingMode == float_round_nearest_even ) {
+            z.high += lastBitMask>>1;
+            if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
+                z.high &= ~ lastBitMask;
+            }
+        }
+        else if ( roundingMode != float_round_to_zero ) {
+            if (   extractFloat128Sign( z )
+                 ^ ( roundingMode == float_round_up ) ) {
+                z.high |= ( a.low != 0 );
+                z.high += roundBitsMask;
+            }
+        }
+        z.high &= ~ roundBitsMask;
+    }
+    if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the quadruple-precision
+floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
+before being returned.  `zSign' is ignored if the result is a NaN.  The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+    int32 aExp, bExp, zExp;
+    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    int32 expDiff;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    expDiff = aExp - bExp;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0x7FFF ) {
+            if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig0 |= LIT64( 0x0001000000000000 );
+        }
+        shift128ExtraRightJamming(
+            bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0x7FFF ) {
+            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig0 |= LIT64( 0x0001000000000000 );
+        }
+        shift128ExtraRightJamming(
+            aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0x7FFF ) {
+            if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+                return propagateFloat128NaN( a, b );
+            }
+            return a;
+        }
+        add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+        if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+        zSig2 = 0;
+        zSig0 |= LIT64( 0x0002000000000000 );
+        zExp = aExp;
+        goto shiftRight1;
+    }
+    aSig0 |= LIT64( 0x0001000000000000 );
+    add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+    --zExp;
+    if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
+    ++zExp;
+ shiftRight1:
+    shift128ExtraRightJamming(
+        zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ roundAndPack:
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the quadruple-
+precision floating-point values `a' and `b'.  If `zSign' is true, the
+difference is negated before being returned.  `zSign' is ignored if the
+result is a NaN.  The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+    int32 aExp, bExp, zExp;
+    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+    int32 expDiff;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    expDiff = aExp - bExp;
+    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+    shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+            return propagateFloat128NaN( a, b );
+        }
+        float_raise( float_flag_invalid );
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig0 < aSig0 ) goto aBigger;
+    if ( aSig0 < bSig0 ) goto bBigger;
+    if ( bSig1 < aSig1 ) goto aBigger;
+    if ( aSig1 < bSig1 ) goto bBigger;
+    return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+        return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig0 |= LIT64( 0x4000000000000000 );
+    }
+    shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+    bSig0 |= LIT64( 0x4000000000000000 );
+ bBigger:
+    sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig0 |= LIT64( 0x4000000000000000 );
+    }
+    shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
+    aSig0 |= LIT64( 0x4000000000000000 );
+ aBigger:
+    sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the quadruple-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_add( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat128Sigs( a, b, aSign );
+    }
+    else {
+        return subFloat128Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the quadruple-precision floating-point
+values `a' and `b'.  The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sub( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat128Sigs( a, b, aSign );
+    }
+    else {
+        return addFloat128Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the quadruple-precision floating-point
+values `a' and `b'.  The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_mul( float128 a, float128 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    bSign = extractFloat128Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if (    ( aSig0 | aSig1 )
+             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+            return propagateFloat128NaN( a, b );
+        }
+        if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+        if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid );
+            z.low = float128_default_nan_low;
+            z.high = float128_default_nan_high;
+            return z;
+        }
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    zExp = aExp + bExp - 0x4000;
+    aSig0 |= LIT64( 0x0001000000000000 );
+    shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
+    mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
+    add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
+    zSig2 |= ( zSig3 != 0 );
+    if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
+        shift128ExtraRightJamming(
+            zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+        ++zExp;
+    }
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the quadruple-precision floating-point value
+`a' by the corresponding value `b'.  The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_div( float128 a, float128 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, zExp;
+    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    bSign = extractFloat128Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+        if ( bExp == 0x7FFF ) {
+            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+            goto invalid;
+        }
+        return packFloat128( zSign, 0x7FFF, 0, 0 );
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+        return packFloat128( zSign, 0, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) {
+            if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+                float_raise( float_flag_invalid );
+                z.low = float128_default_nan_low;
+                z.high = float128_default_nan_high;
+                return z;
+            }
+            float_raise( float_flag_divbyzero );
+            return packFloat128( zSign, 0x7FFF, 0, 0 );
+        }
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    zExp = aExp - bExp + 0x3FFD;
+    shortShift128Left(
+        aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
+    shortShift128Left(
+        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+    if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
+        shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
+        ++zExp;
+    }
+    zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
+    mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+    sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+    while ( (sbits64) rem0 < 0 ) {
+        --zSig0;
+        add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+    }
+    zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
+    if ( ( zSig1 & 0x3FFF ) <= 4 ) {
+        mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+        sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (sbits64) rem1 < 0 ) {
+            --zSig1;
+            add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the quadruple-precision floating-point value `a'
+with respect to the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_rem( float128 a, float128 b )
+{
+    flag aSign, bSign, zSign;
+    int32 aExp, bExp, expDiff;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+    bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1;
+    bits64 sigMean1;
+    sbits64 sigMean0;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    bSig1 = extractFloat128Frac1( b );
+    bSig0 = extractFloat128Frac0( b );
+    bExp = extractFloat128Exp( b );
+    bSign = extractFloat128Sign( b );
+    if ( aExp == 0x7FFF ) {
+        if (    ( aSig0 | aSig1 )
+             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+            return propagateFloat128NaN( a, b );
+        }
+        goto invalid;
+    }
+    if ( bExp == 0x7FFF ) {
+        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( ( bSig0 | bSig1 ) == 0 ) {
+ invalid:
+            float_raise( float_flag_invalid );
+            z.low = float128_default_nan_low;
+            z.high = float128_default_nan_high;
+            return z;
+        }
+        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return a;
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    expDiff = aExp - bExp;
+    if ( expDiff < -1 ) return a;
+    shortShift128Left(
+        aSig0 | LIT64( 0x0001000000000000 ),
+        aSig1,
+        15 - ( expDiff < 0 ),
+        &aSig0,
+        &aSig1
+    );
+    shortShift128Left(
+        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+    q = le128( bSig0, bSig1, aSig0, aSig1 );
+    if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+    expDiff -= 64;
+    while ( 0 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+        q = ( 4 < q ) ? q - 4 : 0;
+        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+        shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
+        shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
+        sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
+        expDiff -= 61;
+    }
+    if ( -64 < expDiff ) {
+        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+        q = ( 4 < q ) ? q - 4 : 0;
+        q >>= - expDiff;
+        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+        expDiff += 52;
+        if ( expDiff < 0 ) {
+            shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+        }
+        else {
+            shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
+        }
+        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+        sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
+    }
+    else {
+        shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
+        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+    }
+    do {
+        alternateASig0 = aSig0;
+        alternateASig1 = aSig1;
+        ++q;
+        sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+    } while ( 0 <= (sbits64) aSig0 );
+    add128(
+        aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+    if (    ( sigMean0 < 0 )
+         || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
+        aSig0 = alternateASig0;
+        aSig1 = alternateASig1;
+    }
+    zSign = ( (sbits64) aSig0 < 0 );
+    if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
+    return
+        normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the quadruple-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sqrt( float128 a )
+{
+    flag aSign;
+    int32 aExp, zExp;
+    bits64 aSig0, aSig1, zSig0, zSig1, zSig2;
+    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    bits64 shiftedRem0, shiftedRem1;
+    float128 z;
+
+    aSig1 = extractFloat128Frac1( a );
+    aSig0 = extractFloat128Frac0( a );
+    aExp = extractFloat128Exp( a );
+    aSign = extractFloat128Sign( a );
+    if ( aExp == 0x7FFF ) {
+        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
+        if ( ! aSign ) return a;
+        goto invalid;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
+ invalid:
+        float_raise( float_flag_invalid );
+        z.low = float128_default_nan_low;
+        z.high = float128_default_nan_high;
+        return z;
+    }
+    if ( aExp == 0 ) {
+        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
+        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+    }
+    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
+    aSig0 |= LIT64( 0x0001000000000000 );
+    zSig0 = estimateSqrt32( aExp, aSig0>>17 );
+    zSig0 <<= 31;
+    shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
+    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
+    if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
+    shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
+    mul64To128( zSig0, zSig0, &term0, &term1 );
+    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+    while ( (sbits64) rem0 < 0 ) {
+        --zSig0;
+        shortShift128Left( 0, zSig0, 1, &term0, &term1 );
+        term1 |= 1;
+        add128( rem0, rem1, term0, term1, &rem0, &rem1 );
+    }
+    shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
+    zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
+    if ( ( zSig1 & 0x3FFF ) <= 5 ) {
+        if ( zSig1 == 0 ) zSig1 = 1;
+        mul64To128( zSig0, zSig1, &term1, &term2 );
+        shortShift128Left( term1, term2, 1, &term1, &term2 );
+        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+        mul64To128( zSig1, zSig1, &term2, &term3 );
+        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (sbits64) rem1 < 0 ) {
+            --zSig1;
+            shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
+            term3 |= 1;
+            add192(
+                rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+    return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq( float128 a, float128 b )
+{
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise.  The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise.  The invalid exception is
+raised if either operand is a NaN.  Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq_signaling( float128 a, float128 b )
+{
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    return
+           ( a.low == b.low )
+        && (    ( a.high == b.high )
+             || (    ( a.low == 0 )
+                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+           );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+cause an exception.  Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le_quiet( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 == 0 );
+    }
+    return
+          aSign ? le128( b.high, b.low, a.high, a.low )
+        : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt_quiet( float128 a, float128 b )
+{
+    flag aSign, bSign;
+
+    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
+              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+         || (    ( extractFloat128Exp( b ) == 0x7FFF )
+              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+       ) {
+        if (    float128_is_signaling_nan( a )
+             || float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        return
+               aSign
+            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                 != 0 );
+    }
+    return
+          aSign ? lt128( b.high, b.low, a.high, a.low )
+        : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
diff --git a/arch/arm/nwfpe/softfloat.h b/arch/arm/nwfpe/softfloat.h
new file mode 100644 (file)
index 0000000..26745a4
--- /dev/null
@@ -0,0 +1,290 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#ifndef __SOFTFLOAT_H__
+#define __SOFTFLOAT_H__
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'.  If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined.  The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+#define FLOATX80
+/* #define FLOAT128 */
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned long int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+    unsigned short high;
+    unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+    unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+extern signed char float_detect_tininess;
+enum {
+    float_tininess_after_rounding  = 0,
+    float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern signed char float_rounding_mode;
+enum {
+    float_round_nearest_even = 0,
+    float_round_to_zero      = 1,
+    float_round_down         = 2,
+    float_round_up           = 3
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+extern signed char float_exception_flags;
+enum {
+    float_flag_inexact   =  1,
+    float_flag_underflow =  2,
+    float_flag_overflow  =  4,
+    float_flag_divbyzero =  8,
+    float_flag_invalid   = 16
+};
+
+ScottB: November 4, 1998
+Changed the enumeration to match the bit order in the FPA11.
+*/
+
+extern signed char float_exception_flags;
+enum {
+    float_flag_invalid   =  1,
+    float_flag_divbyzero =  2,
+    float_flag_overflow  =  4,
+    float_flag_underflow =  8,
+    float_flag_inexact   = 16
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( signed char );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( signed int );
+float64 int32_to_float64( signed int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( signed int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( signed int );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float32_to_int32( float32 );
+signed int float32_to_int32_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+char float32_eq( float32, float32 );
+char float32_le( float32, float32 );
+char float32_lt( float32, float32 );
+char float32_eq_signaling( float32, float32 );
+char float32_le_quiet( float32, float32 );
+char float32_lt_quiet( float32, float32 );
+char float32_is_signaling_nan( float32 );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float64_to_int32( float64 );
+signed int float64_to_int32_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+char float64_eq( float64, float64 );
+char float64_le( float64, float64 );
+char float64_lt( float64, float64 );
+char float64_eq_signaling( float64, float64 );
+char float64_le_quiet( float64, float64 );
+char float64_lt_quiet( float64, float64 );
+char float64_is_signaling_nan( float64 );
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int floatx80_to_int32( floatx80 );
+signed int floatx80_to_int32_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision.  Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern signed char floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+char floatx80_eq( floatx80, floatx80 );
+char floatx80_le( floatx80, floatx80 );
+char floatx80_lt( floatx80, floatx80 );
+char floatx80_eq_signaling( floatx80, floatx80 );
+char floatx80_le_quiet( floatx80, floatx80 );
+char floatx80_lt_quiet( floatx80, floatx80 );
+char floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+signed int float128_to_int32( float128 );
+signed int float128_to_int32_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+char float128_eq( float128, float128 );
+char float128_le( float128, float128 );
+char float128_lt( float128, float128 );
+char float128_eq_signaling( float128, float128 );
+char float128_le_quiet( float128, float128 );
+char float128_lt_quiet( float128, float128 );
+char float128_is_signaling_nan( float128 );
+
+#endif
+
+#endif
index f0d4a86c56358c7376a09ada8b11d80eefb7ed89..6811431723428048a1e7a11292e280a6a0186ad3 100644 (file)
@@ -7,50 +7,64 @@ OUTPUT_ARCH(arm)
 ENTRY(_start)
 SECTIONS
 {
-  _text = .;                   /* Text and read-only data */
-  .text : {
+  _text = .;                   /* Text and read-only data      */
+  .text : { }                  /* Set text start address       */
+
+  __init_begin = .;            /* Init code and data           */
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  __ebsa285_begin = .;
+  .text.ebsa285 : { *(.text.ebsa285) }
+  .data.ebsa285 : { *(.data.ebsa285) }
+  . = ALIGN(4096);
+  __ebsa285_end = .;
+
+  __netwinder_begin = .;
+  .text.netwinder : { *(.text.netwinder) }
+  .data.netwinder : { *(.data.netwinder) }
+  . = ALIGN(4096);
+  __netwinder_end = .;
+
+  .text.real : {               /* Real text segment            */
        *(.text)
        *(.fixup)
        *(.gnu.warning)
-       } = 0x9090
+       }
+
   .text.lock : { *(.text.lock) }       /* out-of-line lock text */
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
-  . = ALIGN(16);               /* Exception table */
+  . = ALIGN(16);               /* Exception table              */
   __start___ex_table = .;
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
-  __start___ksymtab = .;       /* Kernel symbol table */
+  __start___ksymtab = .;       /* Kernel symbol table          */
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
-  _etext = .;                  /* End of text section */
+  _etext = .;                  /* End of text section          */
 
   . = ALIGN(8192);
-  .data : {                    /* Data */
+  .data : {                    /* Data                         */
        *(.init.task)
        *(.data)
        CONSTRUCTORS
        }
 
-  _edata = .;                  /* End of data section */
-
-  . = ALIGN(4096);             /* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
+  _edata = .;                  /* End of data section          */
 
-  __bss_start = .;             /* BSS */
+  __bss_start = .;             /* BSS                          */
   .bss : {
        *(.bss)
        }
   _end = . ;
 
-  /* Stabs debugging sections.  */
+                               /* Stabs debugging sections.    */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
   .stab.excl 0 : { *(.stab.excl) }
index 49be2fe7b77d90b2c0d9684cf5121d79c696efc5..b5ede650874a45970b64a00494c4e53d421e897f 100644 (file)
@@ -95,10 +95,9 @@ CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
@@ -355,7 +354,6 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
index e69cc9ef0d7aa8338079fa3aff1b6a261de34900..1caf1143a71f7e5cbe4fa2744a11964a1bc0a997 100644 (file)
@@ -259,7 +259,6 @@ CONFIG_NFSD=m
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
-CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
index e6023f43b2ce1e9c1d507a320054525f9d7b2df7..9f7b5b1f77cab9155f3fa3427d8907359ec30742 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.91 1999/01/26 11:00:44 jj Exp $
+/*  $Id: signal.c,v 1.92 1999/06/14 05:23:53 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -1194,6 +1194,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
                        default:
                                lock_kernel();
                                sigaddset(&current->signal, signr);
+                               recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
                                do_exit(exit_code);
                                /* NOT REACHED */
index 050ba65dbf2b19792e14f64c000978390e59db8c..ed610942ee9e9973fb0f2c223c06580234a92e15 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.98 1999/06/09 08:23:39 davem Exp $
+/* $Id: sys_sunos.c,v 1.99 1999/06/11 11:40:39 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -197,7 +197,7 @@ asmlinkage int sunos_brk(unsigned long brk)
         * fool it, but this should catch most mistakes.
         */
        freepages = buffermem >> PAGE_SHIFT;
-        freepages += page_cache_size;
+       freepages += atomic_read(&page_cache_size);
        freepages >>= 1;
        freepages += nr_free_pages;
        freepages += nr_swap_pages;
@@ -209,7 +209,7 @@ asmlinkage int sunos_brk(unsigned long brk)
         * Ok, we have probably got enough memory - let it rip.
         */
        current->mm->brk = brk;
-       do_brk(oldbrk, newbrk-oldbrk)
+       do_brk(oldbrk, newbrk-oldbrk);
        retval = 0;
 out:
        up(&current->mm->mmap_sem);
index 051c6560ac583d2cdc80b4ddad3db6b1d9a5b2b9..86eb0581980702175ca5adf6eb1c49716c76fe8f 100644 (file)
@@ -299,7 +299,6 @@ CONFIG_NFSD=m
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
-CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
index 00340d6d52d740ebde0c29df6566f7c20388d944..476d53558cf763507862d980b63709ac243b4bc1 100644 (file)
@@ -34,7 +34,7 @@
  * and that it is in the task area before calling this: this routine does
  * no checking.
  */
-static pte_t *get_page(struct task_struct * tsk,
+static pte_t *ptrace_get_page(struct task_struct * tsk,
        struct vm_area_struct * vma, unsigned long addr, int write)
 {
        pgd_t * pgdir;
@@ -121,7 +121,7 @@ static inline unsigned long get_long(struct task_struct * tsk,
        pte_t * pgtable;
        unsigned long page, retval;
        
-       if (!(pgtable = get_page (tsk, vma, addr, 0))) return 0;
+       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
        if (MAP_NR(page) >= max_mapnr)
@@ -138,7 +138,7 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm
        pte_t *pgtable;
        unsigned long page;
 
-       if (!(pgtable = get_page (tsk, vma, addr, 1))) return;
+       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
        flush_cache_page(vma, addr);
@@ -166,7 +166,7 @@ static inline unsigned int get_int(struct task_struct * tsk,
        unsigned long page;
        unsigned int retval;
        
-       if (!(pgtable = get_page (tsk, vma, addr, 0))) return 0;
+       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 0))) return 0;
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
        if (MAP_NR(page) >= max_mapnr)
@@ -183,7 +183,7 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma
        pte_t *pgtable;
        unsigned long page;
 
-       if (!(pgtable = get_page (tsk, vma, addr, 1))) return;
+       if (!(pgtable = ptrace_get_page (tsk, vma, addr, 1))) return;
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
        flush_cache_page(vma, addr);
@@ -941,7 +941,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                                pt_error_return(regs, EIO);
                                goto flush_and_out;
                        }
-                       pgtable = get_page (child, vma, src, 0);
+                       pgtable = ptrace_get_page (child, vma, src, 0);
                        up(&child->mm->mmap_sem);
                        if (src & ~PAGE_MASK) {
                                curlen = PAGE_SIZE - (src & ~PAGE_MASK);
@@ -988,7 +988,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                                pt_error_return(regs, EIO);
                                goto flush_and_out;
                        }
-                       pgtable = get_page (child, vma, dest, 1);
+                       pgtable = ptrace_get_page (child, vma, dest, 1);
                        up(&child->mm->mmap_sem);
                        if (dest & ~PAGE_MASK) {
                                curlen = PAGE_SIZE - (dest & ~PAGE_MASK);
index e0ba8aa1e2b016ad80c914afe130c086a451f223..247afc77c172f32643d35f91b8c48f5b13908aed 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.40 1999/06/02 19:19:52 jj Exp $
+/*  $Id: signal.c,v 1.41 1999/06/14 05:23:58 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -898,6 +898,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
                        default:
                                lock_kernel();
                                sigaddset(&current->signal, signr);
+                               recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
                                do_exit(exit_code);
                                /* NOT REACHED */
index d425132fdc047ca0f8eac185476259256be628d2..b1190d2447565e7548ad445539f5355384947ff6 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $
+/*  $Id: signal32.c,v 1.48 1999/06/14 05:24:01 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -1336,6 +1336,7 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
                        default:
                                lock_kernel();
                                sigaddset(&current->signal, signr);
+                               recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
                                do_exit(exit_code);
                                /* NOT REACHED */
index 99e010e78a29e88b2ec14cc90823f65054dc971d..d375dc26b48effc653327253e04fefbd562e30e8 100644 (file)
@@ -164,7 +164,7 @@ asmlinkage int sunos_brk(u32 baddr)
         * fool it, but this should catch most mistakes.
         */
        freepages = buffermem >> PAGE_SHIFT;
-        freepages += page_cache_size;
+       freepages += atomic_read(&page_cache_size);
        freepages >>= 1;
        freepages += nr_free_pages;
        freepages += nr_swap_pages;
index 54558152510e89d12fc25cd4a01de448099b0c8b..6ed6cf6a33892c912edf8e26b4638e8ca3512fbf 100644 (file)
@@ -4,15 +4,12 @@
 mainmenu_option next_comment
 comment 'Acorn-specific block devices'
 
-bool '   Support expansion card IDE interfaces' CONFIG_BLK_DEV_IDE_CARDS
-if [ "$CONFIG_BLK_DEV_IDE_CARDS" = "y" ]; then
-  dep_tristate '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_BLK_DEV_IDE
-  dep_tristate '    RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE
-fi
-
-tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
-if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
-  bool '   Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
+if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
+  tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
+  tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
+  if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
+    bool '   Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
+  fi
 fi
 
 endmenu
index c4016ca0d628219e4a25e89bd72bec76d1d0dba2..4db3192b667d2c80e90d2542c2279960562eff1c 100644 (file)
@@ -14,29 +14,11 @@ L_OBJS   :=
 M_OBJS   :=
 MOD_LIST_NAME := ACORN_BLOCK_MODULES
 
-ifeq ($(CONFIG_ARCH_ARC),y)
-  ifeq ($(CONFIG_BLK_DEV_FD),y)
-    L_OBJS += fd1772.o fd1772dma.o
-  else
-    ifeq ($(CONFIG_BLK_DEV_FD),m)
-      M_OBJS += fd1772_mod.o
-    endif
-  endif
-endif
-
-ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y)
-  L_OBJS += ide-ics.o
-else
-  ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),m)
-    M_OBJS += ide-ics.o
-  endif
-endif
-
-ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y)
-  L_OBJS += ide-rapide.o
+ifeq ($(CONFIG_BLK_DEV_FD1772),y)
+  L_OBJS += fd1772.o fd1772dma.o
 else
-  ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),m)
-    M_OBJS += ide-rapide.o
+  ifeq ($(CONFIG_BLK_DEV_FD1772),m)
+    M_OBJS += fd1772_mod.o
   endif
 endif
 
index 02a2307d60ce1e276aa762c656a3d5056f2d92e8..8ee368ac95c54666883758199ccee6791fb5d586 100644 (file)
  *               I wish I knew why that timer didn't work.....
  *
  *     16/11/96 - Fiddled and frigged for 2.0.18
+ *
+ * DAG 30/01/99 - Started frobbing for 2.2.1
  */
 
 #include <linux/sched.h>
 #include <asm/dma.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
+#include <asm/ioc.h>
 #include <asm/irq.h>
-#include <asm/irq-no.h>
 #include <asm/pgtable.h>
 #include <asm/segment.h>
 
 #define MAJOR_NR FLOPPY_MAJOR
 #define FLOPPY_DMA 0
-#include "blk.h"
+#include <linux/blk.h>
 
 /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
  * little additional rework in this file). But I'm not yet sure if
index f145628e7a9604175d7ea95eebe08507e09fe25a..7964435443ecc39585b5e6d979168baef04e4f23 100644 (file)
@@ -4,45 +4,45 @@
 .text
 
 
-  .global _fdc1772_dataaddr
-_fdc1772_fiqdata:
+  .global fdc1772_dataaddr
+fdc1772_fiqdata:
 @ Number of bytes left to DMA
-  .global _fdc1772_bytestogo
-_fdc1772_bytestogo:
+  .global fdc1772_bytestogo
+fdc1772_bytestogo:
   .word 0
 @ Place to put/get data from in DMA
-  .global _fdc1772_dataaddr
-_fdc1772_dataaddr:
+  .global fdc1772_dataaddr
+fdc1772_dataaddr:
   .word 0
   
-  .global _fdc1772_fdc_int_done
-_fdc1772_fdc_int_done:
+  .global fdc1772_fdc_int_done
+fdc1772_fdc_int_done:
   .word 0
-  .global _fdc1772_comendstatus
-_fdc1772_comendstatus:
+  .global fdc1772_comendstatus
+fdc1772_comendstatus:
   .word 0
 
 @ We hang this off DMA channel 1
-    .global _fdc1772_comendhandler
-_fdc1772_comendhandler:
+    .global fdc1772_comendhandler
+fdc1772_comendhandler:
   mov      r8,#IOC_BASE
   ldrb     r9,[r8,#0x34]    @ IOC FIQ status
   tst      r9,#2
   subeqs   pc,r14,#4        @ should I leave a space here
   orr      r9,r8,#0x10000   @ FDC base
-  adr      r8,_fdc1772_fdc_int_done
+  adr      r8,fdc1772_fdc_int_done
   ldrb     r10,[r9,#0]  @ FDC status
   mov      r9,#1        @ Got a FIQ flag
   stmia    r8,{r9,r10}
   subs     pc,r14,#4
 
 
-    .global _fdc1772_dma_read
-_fdc1772_dma_read:
+    .global fdc1772_dma_read
+fdc1772_dma_read:
   mov      r8,#IOC_BASE
   ldrb     r9,[r8,#0x34]    @ IOC FIQ status
   tst      r9,#1
-  beq      _fdc1772_dma_read_notours
+  beq      fdc1772_dma_read_notours
   orr      r8,r8,#0x10000   @ FDC base
   ldrb     r10,[r8,#0xc]   @ Read from FDC data reg (also clears interrupt)
   ldmia    r11,{r8,r9}
@@ -51,19 +51,19 @@ _fdc1772_dma_read:
   strplb   r10,[r9],#1     @ Store the data and increment the pointer
   stmplia  r11,{r8,r9}     @ Update count/pointers
   @ Handle any other interrupts if there are any
-_fdc1772_dma_read_notours:
+fdc1772_dma_read_notours:
   @ Cant branch because this code has been copied down to the FIQ vector
   ldr pc,[pc,#-4]
-  .word _fdc1772_comendhandler
-  .global _fdc1772_dma_read_end
-_fdc1772_dma_read_end:
+  .word fdc1772_comendhandler
+  .global fdc1772_dma_read_end
+fdc1772_dma_read_end:
 
-    .global _fdc1772_dma_write
-_fdc1772_dma_write:
+    .global fdc1772_dma_write
+fdc1772_dma_write:
   mov      r8,#IOC_BASE
   ldrb     r9,[r8,#0x34]    @ IOC FIQ status
   tst      r9,#1
-  beq      _fdc1772_dma_write_notours
+  beq      fdc1772_dma_write_notours
   orr      r8,r8,#0x10000   @ FDC base
   ldmia    r11,{r9,r10}
   subs     r9,r9,#1        @ One less byte to go
@@ -72,23 +72,23 @@ _fdc1772_dma_write:
   strplb   r12,[r8,#0xc]   @ write it to FDC data reg
   stmplia  r11,{r9,r10}    @ Update count and pointer - should clear interrupt
   @ Handle any other interrupts
-_fdc1772_dma_write_notours:
+fdc1772_dma_write_notours:
   @ Cant branch because this code has been copied down to the FIQ vector
   ldr pc,[pc,#-4]
-  .word _fdc1772_comendhandler
+  .word fdc1772_comendhandler
 
-  .global _fdc1772_dma_write_end
-_fdc1772_dma_write_end:
+  .global fdc1772_dma_write_end
+fdc1772_dma_write_end:
   
 
 @ Setup the FIQ R11 to point to the data and store the count, address
 @ for this dma
 @ R0=count
 @ R1=address
-  .global _fdc1772_setupdma
-_fdc1772_setupdma:
+  .global fdc1772_setupdma
+fdc1772_setupdma:
        @ The big job is flipping in and out of FIQ mode
-       adr     r2,_fdc1772_fiqdata     @ This is what we really came here for
+       adr     r2,fdc1772_fiqdata      @ This is what we really came here for
   stmia  r2,{r0,r1}
        mov     r3, pc
        teqp    pc,#0x0c000001  @ Disable FIQs, IRQs and switch to FIQ mode
diff --git a/drivers/acorn/block/ide-ics.c b/drivers/acorn/block/ide-ics.c
deleted file mode 100644 (file)
index 24ac280..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * linux/arch/arm/drivers/block/ide-ics.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- *  08-06-1996 RMK     Created
- *  12-09-1997 RMK     Added interrupt enable/disable
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-#include "../../block/ide.h"
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS        2
-
-#define ICS_IDENT_OFFSET               0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT          0x000
-#define ICS_ARCIN_V5_INTROFFSET                0x001
-#define ICS_ARCIN_V5_IDEOFFSET         0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET      0xae0
-#define ICS_ARCIN_V5_IDESTEPPING       4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1       0x800
-#define ICS_ARCIN_V6_INTROFFSET_1      0x880
-#define ICS_ARCIN_V6_INTRSTAT_1                0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1    0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2       0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2      0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2                0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2    0xce0
-#define ICS_ARCIN_V6_IDESTEPPING       4
-
-static const card_ids icside_cids[] = {
-       { MANU_ICS, PROD_ICS_IDE },
-       { 0xffff, 0xffff }
-};
-
-typedef enum {
-       ics_if_unknown,
-       ics_if_arcin_v5,
-       ics_if_arcin_v6
-} iftype_t;
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS][MAX_IFS];
-
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-       unsigned int memc_port = (unsigned int)ec->irq_data;
-       outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-       unsigned int memc_port = (unsigned int)ec->irq_data;
-       inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-       icside_irqenable_arcin_v5,
-       icside_irqdisable_arcin_v5,
-       NULL,
-       NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-       unsigned int ide_base_port = (unsigned int)ec->irq_data;
-       outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-       outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-       unsigned int ide_base_port = (unsigned int)ec->irq_data;
-       inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-       inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-       icside_irqenable_arcin_v6,
-       icside_irqdisable_arcin_v6,
-       NULL,
-       NULL
-};
-
-
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t icside_identifyif (struct expansion_card *ec)
-{
-       unsigned int addr;
-       iftype_t iftype;
-       int id = 0;
-
-       iftype = ics_if_unknown;
-
-       addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-       id = inb (addr) & 1;
-       id |= (inb (addr + 1) & 1) << 1;
-       id |= (inb (addr + 2) & 1) << 2;
-       id |= (inb (addr + 3) & 1) << 3;
-
-       switch (id) {
-       case 0: /* A3IN */
-               printk ("icside: A3IN unsupported\n");
-               break;
-
-       case 1: /* A3USER */
-               printk ("icside: A3USER unsupported\n");
-               break;
-
-       case 3: /* ARCIN V6 */
-               printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-               iftype = ics_if_arcin_v6;
-               break;
-
-       case 15:/* ARCIN V5 (no id) */
-               printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-               iftype = ics_if_arcin_v5;
-               break;
-
-       default:/* we don't know - complain very loudly */
-               printk ("icside: ***********************************\n");
-               printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-               printk ("icside: ***********************************\n");
-               printk ("icside: please report this to: linux@arm.uk.linux.org\n");
-               printk ("icside: defaulting to ARCIN V5\n");
-               iftype = ics_if_arcin_v5;
-               break;
-       }
-
-       return iftype;
-}
-
-static int icside_register_port(unsigned long dataport, unsigned long ctrlport, int stepping, int irq)
-{
-       hw_regs_t hw;
-       int i;
-
-       memset(&hw, 0, sizeof(hw));
-
-       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-               hw.io_ports[i] = (ide_ioreg_t)dataport;
-               dataport += 1 << stepping;
-       }
-       hw.io_ports[IDE_CONTROL_OFFSET] = ctrlport;
-       hw.irq = irq;
-
-       return ide_register_hw(&hw, NULL);
-}
-
-/* Prototype: icside_register (struct expansion_card *ec)
- * Purpose  : register an ICS IDE card with the IDE driver
- * Notes    : we make sure that interrupts are disabled from the card
- */
-static inline void icside_register (struct expansion_card *ec, int index)
-{
-       unsigned long port;
-
-       result[index][0] = -1;
-       result[index][1] = -1;
-
-       switch (icside_identifyif (ec)) {
-       case ics_if_unknown:
-       default:
-               printk ("** Warning: ICS IDE Interface unrecognised! **\n");
-               break;
-
-       case ics_if_arcin_v5:
-               port = ecard_address (ec, ECARD_MEMC, 0);
-               ec->irqaddr = ioaddr(port + ICS_ARCIN_V5_INTRSTAT);
-               ec->irqmask = 1;
-               ec->irq_data = (void *)port;
-               ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
-               /*
-                * Be on the safe side - disable interrupts
-                */
-               inb (port + ICS_ARCIN_V5_INTROFFSET);
-               result[index][0] = icside_register_port(port + ICS_ARCIN_V5_IDEOFFSET,
-                                                       port + ICS_ARCIN_V5_IDEALTOFFSET,
-                                                       ICS_ARCIN_V5_IDESTEPPING,
-                                                       ec->irq);
-               result[index][1] = -1;
-               break;
-
-       case ics_if_arcin_v6:
-               port = ecard_address (ec, ECARD_IOC, ECARD_FAST);
-               ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1);
-               ec->irqmask = 1;
-               ec->irq_data = (void *)port;
-               ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-               /*
-                * Be on the safe side - disable interrupts
-                */
-               inb (port + ICS_ARCIN_V6_INTROFFSET_1);
-               inb (port + ICS_ARCIN_V6_INTROFFSET_2);
-
-               result[index][0] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_1,
-                                                       port + ICS_ARCIN_V6_IDEALTOFFSET_1,
-                                                       ICS_ARCIN_V6_IDESTEPPING,
-                                                       ec->irq);
-               result[index][1] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_2,
-                                                       port + ICS_ARCIN_V6_IDEALTOFFSET_2,
-                                                       ICS_ARCIN_V6_IDESTEPPING,
-                                                       ec->irq);
-               break;
-       }               
-}
-
-int icside_init (void)
-{
-       int i;
-
-       for (i = 0; i < MAX_ECARDS; i++)
-               ec[i] = NULL;
-
-       ecard_startfind ();
-
-       for (i = 0; ; i++) {
-               if ((ec[i] = ecard_find (0, icside_cids)) == NULL)
-                       break;
-
-               ecard_claim (ec[i]);
-               icside_register (ec[i], i);
-       }
-
-       for (i = 0; i < MAX_ECARDS; i++)
-               if (ec[i] && result[i][0] < 0 && result[i][1] < 0) {
-                       ecard_release (ec[i]);
-                       ec[i] = NULL;
-               }
-       return 0;
-}
-
-#ifdef MODULE
-int init_module (void)
-{
-       return icside_init();
-}
-
-void cleanup_module (void)
-{
-       int i;
-
-       for (i = 0; i < MAX_ECARDS; i++)
-               if (ec[i]) {
-                       if (result[i][0] >= 0)
-                               ide_unregister (result[i][0]);
-
-                       if (result[i][1] >= 0)
-                               ide_unregister (result[i][1]);
-                               
-                       ecard_release (ec[i]);
-                       ec[i] = NULL;
-               }
-}
-#endif
-
diff --git a/drivers/acorn/block/ide-rapide.c b/drivers/acorn/block/ide-rapide.c
deleted file mode 100644 (file)
index d142ceb..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * linux/arch/arm/drivers/block/ide-rapide.c
- *
- * Copyright (c) 1996-1998 Russell King.
- *
- * Changelog:
- *  08-06-1996 RMK     Created
- *  13-04-1998 RMK     Added manufacturer and product IDs
- */
-
-#include <linux/module.h>
-#include <linux/malloc.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <asm/ecard.h>
-#include <asm/ide.h>
-
-#include "../../block/ide.h"
-
-static const card_ids rapide_cids[] = {
-       { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-       { 0xffff, 0xffff }
-};
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS];
-
-static inline int rapide_register(struct expansion_card *ec)
-{
-       unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-       ide_ioregspec_t spec;
-
-       spec.base = port;
-       spec.ctrl = port + 0x206;
-       spec.offset = 1 << 4;
-       spec.irq = ec->irq;
-
-       return ide_register_port(&spec);
-}
-
-int rapide_init(void)
-{
-       int i;
-
-       for (i = 0; i < MAX_ECARDS; i++)
-               ec[i] = NULL;
-
-       ecard_startfind();
-
-       for (i = 0; ; i++) {
-               if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
-                       break;
-
-               ecard_claim(ec[i]);
-               result[i] = rapide_register(ec[i]);
-       }
-       for (i = 0; i < MAX_ECARDS; i++)
-               if (ec[i] && result[i] < 0) {
-                       ecard_release(ec[i]);
-                       ec[i] = NULL;
-       }
-       return 0;
-}
-
-#ifdef MODULE
-
-int init_module (void)
-{
-       return rapide_init();
-}
-
-void cleanup_module (void)
-{
-       int i;
-
-       for (i = 0; i < MAX_ECARDS; i++)
-               if (ec[i]) {
-                       unsigned long port;
-                       port = ecard_address(ec[i], ECARD_MEMC, 0);
-
-                       ide_unregister_port(port, ec[i]->irq, 16);
-                       ecard_release(ec[i]);
-                       ec[i] = NULL;
-               }
-}
-#endif
-
index 1efc5ece775ad2f4319b9737e5c49e18590b5fd2..c90cbd41ce21e34ada85d39689bd348df0a48c7d 100644 (file)
@@ -1,44 +1,43 @@
-@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400
-@   motherboard on ST506 podules.
-@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996
+@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
+@   motherboard and on ST506 expansion podules.
+@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
 
 #include <asm/assembler.h>
  
-_hdc63463_irqdata:
+hdc63463_irqdata:
 @ Controller base address
-  .global _hdc63463_baseaddress
-_hdc63463_baseaddress:
+  .global hdc63463_baseaddress
+hdc63463_baseaddress:
   .word 0
 
-  .global _hdc63463_irqpolladdress
-_hdc63463_irqpolladdress:
+  .global hdc63463_irqpolladdress
+hdc63463_irqpolladdress:
   .word 0
  
-  .global _hdc63463_irqpollmask
-_hdc63463_irqpollmask:
+  .global hdc63463_irqpollmask
+hdc63463_irqpollmask:
   .word 0
 
 @ where to read/write data  from the kernel data space
-  .global _hdc63463_dataptr
-_hdc63463_dataptr:
+  .global hdc63463_dataptr
+hdc63463_dataptr:
   .word 0
 
 @ Number of bytes left to transfer
-  .global _hdc63463_dataleft
-_hdc63463_dataleft:
+  .global hdc63463_dataleft
+hdc63463_dataleft:
   .word 0
 
 @ -------------------------------------------------------------------------
 @ hdc63463_writedma: DMA from host to controller
 @  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
 @                      r3=data ptr, r4=data left, r5,r6=temporary
-  .global _hdc63463_writedma
-_hdc63463_writedma:
+  .global hdc63463_writedma
+hdc63463_writedma:
   stmfd sp!,{r4-r7}
-  adr r5,_hdc63463_irqdata
+  adr r5,hdc63463_irqdata
   ldmia r5,{r0,r1,r2,r3,r4}
 
-
 writedma_again:
 
   @ test number of remaining bytes to transfer
@@ -89,12 +88,12 @@ writedma_loop:
 
   @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
   @ sub r0,r0,#32+8
-  @ adr r2,_hdc63463_irqdata
+  @ adr r2,hdc63463_irqdata
   @ ldr r2,[r2,#8]
   @ b writedma_again
 
 writedma_end:
-  adr r5,_hdc63463_irqdata+12
+  adr r5,hdc63463_irqdata+12
   stmia r5,{r3,r4}
   ldmfd sp!,{r4-r7}
   RETINSTR(mov,pc,lr)
@@ -103,10 +102,10 @@ writedma_end:
 @ hdc63463_readdma: DMA from controller to host
 @  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
 @                      r3=data ptr, r4=data left, r5,r6=temporary
-  .global _hdc63463_readdma
-_hdc63463_readdma:
+  .global hdc63463_readdma
+hdc63463_readdma:
   stmfd sp!,{r4-r7}
-  adr r5,_hdc63463_irqdata
+  adr r5,hdc63463_irqdata
   ldmia r5,{r0,r1,r2,r3,r4}
 
 readdma_again:
@@ -157,7 +156,7 @@ readdma_loop:
   @ b readdma_again
 
 readdma_end:
-  adr r5,_hdc63463_irqdata+12
+  adr r5,hdc63463_irqdata+12
   stmia r5,{r3,r4}
   ldmfd sp!,{r4-r7}
   RETINSTR(mov,pc,lr)
index 219f1003402740392d0ff7469790ca7992be4aab..7a8ea6f8eff10829f62037b1fb2afc05565b08bb 100644 (file)
 #include <asm/dma.h>
 #include <asm/hardware.h>
 #include <asm/ecard.h>
+#include <asm/ioc.h>
 
 /*
  * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
@@ -261,7 +262,9 @@ static struct cont {
        void (*done) (int st);  /* done handler */
 } *cont = NULL;
 
+#if 0
 static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
+#endif
 
 int number_mfm_drives = 1;
 
diff --git a/drivers/acorn/char/Config.in b/drivers/acorn/char/Config.in
deleted file mode 100644 (file)
index ede0a82..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-if [ "$CONFIG_SERIAL" != "n" ]; then
-  tristate '   Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
-  tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
-fi
-
-if [ "$CONFIG_MOUSE" = "y" ]; then
-  if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-    if [ "$CONFIG_ARCH_RPC" != "y" ]; then
-      define_bool CONFIG_KBDMOUSE y
-    else
-      define_bool CONFIG_RPCMOUSE y
-    fi
-  fi
-fi
-
index ecbbfe90c007f036b7f6ed2d466ae93af0b3d60c..c3c6f67baddd7e18ce2fc7d74d124b1a09ea4150 100644 (file)
@@ -9,20 +9,21 @@
 # parent makes..
 #
 
-L_TARGET := acorn-char.a
-M_OBJS   :=
-L_OBJS   :=
+L_TARGET       := acorn-char.a
+M_OBJS         :=
+L_OBJS         :=
 
-ifeq ($(MACHINE),rpc)
-  MOUSE_OBJS += mouse_rpc.o
-  L_OBJS += keyb_ps2.o
-endif
+L_OBJS_arc     := keyb_arc.o
+L_OBJS_a5k     := keyb_arc.o
+L_OBJS_rpc     := keyb_ps2.o
 
-ifeq ($(CONFIG_MOUSE),y)
-  LX_OBJS += $(MOUSE_OBJS)
-else
-  ifeq ($(CONFIG_MOUSE),m)
-    MX_OBJS += $(MOUSE_OBJS)
+ifeq ($(MACHINE),rpc)
+  ifeq ($(CONFIG_MOUSE),y)
+    LX_OBJS += mouse_rpc.o
+  else
+    ifeq ($(CONFIG_MOUSE),m)
+      MX_OBJS += mouse_rpc.o
+    endif
   endif
 endif
 
@@ -42,4 +43,6 @@ else
   endif
 endif
 
+L_OBJS += $(L_OBJS_$(MACHINE))
+
 include $(TOPDIR)/Rules.make
diff --git a/drivers/acorn/char/keyb_arc.c b/drivers/acorn/char/keyb_arc.c
new file mode 100644 (file)
index 0000000..01c496a
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * linux/arch/arm/drivers/char1/keyb_arc.c
+ *
+ * Acorn keyboard driver for ARM Linux.
+ *
+ * The Acorn keyboard appears to have a ***very*** buggy reset protocol -
+ * every reset behaves differently.  We try to get round this by attempting
+ * a few things...
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/tty.h>
+#include <linux/kbd_kern.h>
+#include <linux/delay.h>
+
+#include <asm/bitops.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/ioc.h>
+#include <asm/hardware.h>
+
+#include "../../char/mouse.h"
+
+extern void kbd_reset_kdown(void);
+
+#define VERSION 108
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+static char kbd_txval[4];
+static unsigned char kbd_txhead, kbd_txtail;
+#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3)
+static int kbd_id = -1;
+static struct wait_queue *kbd_waitq;
+#ifdef CONFIG_KBDMOUSE
+static int mousedev;
+#endif
+
+/*
+ * Protocol codes to send the keyboard.
+ */
+#define HRST 0xff      /* reset keyboard */
+#define RAK1 0xfe      /* reset response */
+#define RAK2 0xfd      /* reset response */
+#define BACK 0x3f      /* Ack for first keyboard pair */
+#define SMAK 0x33      /* Last data byte ack (key scanning + mouse movement scanning) */
+#define MACK 0x32      /* Last data byte ack (mouse movement scanning) */
+#define SACK 0x31      /* Last data byte ack (key scanning) */
+#define NACK 0x30      /* Last data byte ack (no scanning, mouse data) */
+#define RQMP 0x22      /* Request mouse data */
+#define PRST 0x21      /* nothing */
+#define RQID 0x20      /* Request ID */
+
+#define UP_FLAG 1
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char a5kkbd_sysrq_xlate[] = 
+{
+    27,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,
+   '`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+   '8',  '9',  '0',  '-',  '=',  '£',  127,    0,
+     0,    0,    0,  '/',  '*',  '#',    9,  'q',
+   'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',
+   'p',  '[',  ']', '\\',  22,    23,   25,  '7',
+   '8',  '9',  '-',    0,  'a',  's',  'd',  'f',
+   'g',  'h',  'j',  'k',  'l',  ';', '\'',   13,
+   '4',  '5',  '6',  '+',    0,    0,  'z',  'x',
+   'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/',
+     0,    0,  '1',  '2',  '3',    0,    0,  ' ',
+     0,    0,    0,    0,    0,  '0',  '.',   10,
+     0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,
+};
+#endif
+
+/*
+ * This array converts the scancode that we get from the keyboard to the
+ * real rows/columns on the A5000 keyboard.  This might be keyboard specific...
+ *
+ * It is these values that we use to maintain the key down array.  That way, we
+ * should pick up on the ghost key presses (which is what happens when you press
+ * three keys, and the keyboard thinks you have pressed four!)
+ *
+ * Row 8 (0x80+c) is actually a column with one key per row.  It is isolated from
+ * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
+ *
+ * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
+ * them, and can't process them for ghosts).  This does however, cause problems with
+ * autorepeat processing...
+ */
+static unsigned char scancode_2_colrow[256] = {
+  0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
+  0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
+  0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
+  0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
+  0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
+  0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
+  0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
+};
+
+#define BITS_PER_SHORT (8*sizeof(unsigned short))
+static unsigned short ghost_down[128/BITS_PER_SHORT];
+
+static void a5kkbd_key(unsigned int keycode, unsigned int up_flag)
+{
+       unsigned int real_keycode;
+
+       if (keycode > 0x72) {
+#ifdef KBD_REPORT_UNKN
+               printk ("kbd: unknown scancode 0x%04x\n", keycode);
+#endif
+               return;
+       }
+       if (keycode >= 0x70) {
+#ifdef CONFIG_KBDMOUSE
+               if (mousedev >= 0)
+                       switch (keycode) {
+                       case 0x70: /* Left mouse button */
+                               busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0);
+                               break;
+
+                       case 0x71: /* Middle mouse button */
+                               busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0);
+                               break;
+
+                       case 0x72:/* Right mouse button */
+                               busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0);
+                               break;
+                       }
+#endif
+               return;
+       }
+
+       /*
+        * We have to work out if we accept this key press as a real key, or
+        * if it is a ghost.  IE. If you press three keys, the keyboard will think
+        * that you've pressed a fourth: (@ = key down, # = ghost)
+        *
+        *   0 1 2 3 4 5 6 7
+        *   | | | | | | | |
+        * 0-+-+-+-+-+-+-+-+-
+        *   | | | | | | | |
+        * 1-+-@-+-+-+-@-+-+-
+        *   | | | | | | | |
+        * 2-+-+-+-+-+-+-+-+-
+        *   | | | | | | | |
+        * 3-+-@-+-+-+-#-+-+-
+        *   | | | | | | | |
+        *
+        * This is what happens when you have a matrix keyboard...
+        */
+
+       real_keycode = scancode_2_colrow[keycode];
+
+       if ((real_keycode & 0x80) == 0) {
+               int rr, kc = (real_keycode >> 4) & 7;
+               int cc;
+               unsigned short res, kdownkc;
+
+               kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
+
+               for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
+                       if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
+                               /*
+                                * we have found a second row with at least one key pressed in the
+                                * same column.
+                                */
+                               for (cc = 0; res; res >>= 1)
+                                       cc += (res & 1);
+                               if (cc > 1)
+                                       return; /* ignore it */
+                       }
+               if (up_flag)
+                       clear_bit (real_keycode, ghost_down);
+               else
+                       set_bit (real_keycode, ghost_down);
+       }
+
+       handle_scancode(keycode, !up_flag);
+}
+
+static inline void a5kkbd_sendbyte(unsigned char val)
+{
+       kbd_txval[kbd_txhead] = val;
+       KBD_INCTXPTR(kbd_txhead);
+       enable_irq(IRQ_KEYBOARDTX);
+}
+
+static inline void a5kkbd_reset(void)
+{
+       int i;
+
+       for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++)
+               ghost_down[i] = 0;
+
+       kbd_reset_kdown();
+}
+
+void a5kkbd_leds(unsigned char leds)
+{
+       leds =  ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
+               ((leds & (1<<VC_CAPSLOCK))?1:0);
+       a5kkbd_sendbyte(leds);
+}
+
+/* Keyboard states:
+ *  0 initial reset condition, receive HRST, send RRAK1
+ *  1 Sent RAK1, wait for RAK1, send RRAK2
+ *  2 Sent RAK2, wait for RAK2, send SMAK or RQID
+ *  3 Sent RQID, expect KBID, send SMAK
+ *  4 Sent SMAK, wait for anything
+ *  5 Wait for second keyboard nibble for key pressed
+ *  6 Wait for second keyboard nibble for key released
+ *  7 Wait for second part of mouse data
+ *
+ * This function returns 1 when we successfully enter the IDLE state
+ * (and hence need to do some keyboard processing).
+ */
+#define KBD_INITRST    0
+#define KBD_RAK1       1
+#define KBD_RAK2       2
+#define KBD_ID         3
+#define KBD_IDLE       4
+#define KBD_KEYDOWN    5
+#define KBD_KEYUP      6
+#define KBD_MOUSE      7
+
+static int handle_rawcode(unsigned int keyval)
+{
+       static signed char kbd_mousedx = 0;
+              signed char kbd_mousedy;
+       static unsigned char kbd_state = KBD_INITRST;
+       static unsigned char kbd_keyhigh = 0;
+
+       if (keyval == HRST && kbd_state != KBD_INITRST && kbd_state != KBD_ID) {
+               a5kkbd_sendbyte (HRST);
+               a5kkbd_reset ();
+               kbd_state = KBD_INITRST;
+       } else switch(kbd_state) {
+       case KBD_INITRST:                       /* hard reset - sent HRST */
+               if (keyval == HRST) {
+                       a5kkbd_sendbyte (RAK1);
+                       kbd_state = KBD_RAK1;
+               } else if (keyval == RAK1) {
+                       /* Some A5000 keyboards are very fussy and don't follow Acorn's
+                        * specs - this appears to fix them, but them it might stop
+                        * them from being initialised.
+                        *  fix by Philip Blundell
+                        */
+                       printk(KERN_DEBUG "keyboard sent early RAK1 -- ignored\n");
+               } else
+                       goto kbd_wontreset;
+               break;
+
+       case KBD_RAK1:                          /* sent RAK1 - expect RAK1 and send RAK2 */
+               if (keyval == RAK1) {
+                       a5kkbd_sendbyte (RAK2);
+                       kbd_state = KBD_RAK2;
+               } else
+                       goto kbd_wontreset;
+               break;
+
+       case KBD_RAK2:                          /* Sent RAK2 - expect RAK2 and send either RQID or SMAK */
+               if (keyval == RAK2) {
+                       if (kbd_id == -1) {
+                               a5kkbd_sendbyte (NACK);
+                               a5kkbd_sendbyte (RQID);
+                               kbd_state = KBD_ID;
+                       } else {
+                               a5kkbd_sendbyte (SMAK);
+                               kbd_state = KBD_IDLE;
+                       }
+               } else
+                       goto kbd_wontreset;
+               break;
+
+       case KBD_ID:                            /* Sent RQID - expect KBID */
+               if (keyval == HRST) {
+                       kbd_id = -2;
+                       a5kkbd_reset ();
+                       a5kkbd_sendbyte (HRST);
+                       kbd_state = KBD_INITRST;
+                       wake_up (&kbd_waitq);
+               } else if ((keyval & 0xc0) == 0x80) {
+                       kbd_id = keyval & 0x3f;
+                       a5kkbd_sendbyte (SMAK);
+                       kbd_state = KBD_IDLE;
+                       wake_up (&kbd_waitq);
+               }
+               break;
+
+       case KBD_IDLE:                          /* Send SMAK, ready for any reply */
+               switch (keyval & 0xf0) {
+               default:        /* 0x00 - 0x7f */
+                       kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
+                       kbd_state   = KBD_MOUSE;
+                       a5kkbd_sendbyte (BACK);
+                       break;
+
+               case 0x80:
+               case 0x90:
+               case 0xa0:
+               case 0xb0:
+                       if (kbd_id == -1)
+                               kbd_id = keyval & 0x3f;
+                       break;
+
+               case 0xc0:
+                       kbd_keyhigh = keyval;
+                       kbd_state   = KBD_KEYDOWN;
+                       a5kkbd_sendbyte (BACK);
+                       break;
+
+               case 0xd0:
+                       kbd_keyhigh = keyval;
+                       kbd_state   = KBD_KEYUP;
+                       a5kkbd_sendbyte (BACK);
+                       break;
+
+               case 0xe0:
+               case 0xf0:
+                       goto kbd_error;
+               }
+               break;
+
+       case KBD_KEYDOWN:
+               if ((keyval & 0xf0) != 0xc0)
+                       goto kbd_error;
+               else {
+                       kbd_state = KBD_IDLE;
+                       a5kkbd_sendbyte (SMAK);
+                       if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
+                               a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), 0);
+               }
+               break;
+
+       case KBD_KEYUP:
+               if ((keyval & 0xf0) != 0xd0)
+                       goto kbd_error;
+               else {
+                       kbd_state = KBD_IDLE;
+                       a5kkbd_sendbyte (SMAK);
+                       if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
+                               a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), UP_FLAG);
+               }
+               break;
+
+       case KBD_MOUSE:
+               if (keyval & 0x80)
+                       goto kbd_error;
+               else {
+                       kbd_state = KBD_IDLE;
+                       a5kkbd_sendbyte (SMAK);
+                       kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
+#ifdef CONFIG_KBDMOUSE
+                       if (mousedev >= 0)
+                               busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy);
+#endif
+               }
+       }
+       return kbd_state == KBD_IDLE ? 1 : 0;
+
+kbd_wontreset:
+#ifdef KBD_REPORT_ERR
+       printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n",
+               kbd_state, keyval);
+#endif
+       mdelay(1);
+       inb(IOC_KARTRX);
+       a5kkbd_sendbyte (HRST);
+       kbd_state = KBD_INITRST;
+       return 0;
+
+kbd_error:
+#ifdef KBD_REPORT_ERR
+       printk ("kbd: keyboard out of sync - resetting\n");
+#endif
+       a5kkbd_sendbyte (HRST);
+       kbd_state = KBD_INITRST;
+       return 0;
+}
+
+static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+{
+       kbd_pt_regs = regs;
+       if (handle_rawcode(inb(IOC_KARTRX)))
+               mark_bh (KEYBOARD_BH);
+}
+
+static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+{
+       outb (kbd_txval[kbd_txtail], IOC_KARTTX);
+       KBD_INCTXPTR(kbd_txtail);
+       if (kbd_txtail == kbd_txhead)
+               disable_irq(irq);
+}
+
+#ifdef CONFIG_KBDMOUSE
+static struct busmouse a5kkbd_mouse = {
+       6, "kbdmouse", NULL, NULL, 7
+};
+#endif
+
+__initfunc(void a5kkbd_init_hw (void))
+{
+       unsigned long flags;
+
+       save_flags_cli (flags);
+       if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
+               panic("Could not allocate keyboard transmit IRQ!");
+       disable_irq (IRQ_KEYBOARDTX);
+       if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
+               panic("Could not allocate keyboard receive IRQ!");
+       (void)inb(IOC_KARTRX);
+       restore_flags (flags);
+
+       a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */
+
+       /* wait 1s for keyboard to initialise */
+       interruptible_sleep_on_timeout(&kbd_waitq, HZ);
+
+#ifdef CONFIG_KBDMOUSE
+       mousedev = register_busmouse(&a5kkbd_mouse);
+       if (mousedev < 0)
+               printk(KERN_ERR "Unable to register mouse driver\n");
+#endif
+
+       printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100);
+       if (kbd_id != -1)
+             printk ("id=%d ", kbd_id);
+       printk ("English)\n");
+}
index 4af051f444e5a86296f91ef02ee8afc4c1a8f0f3..3fa8a03adf178c7fb297b7898aec9904d036dace 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
+#include <asm/iomd.h>
 #include <asm/system.h>
 
 extern void kbd_reset_kdown(void);
@@ -221,14 +222,7 @@ unsigned char ps2kbd_sysrq_xlate[] =
 };
 #endif
 
-int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p)
-{
-       *uf_p = scancode & 0200;
-       *keycode_p = scancode & 0x7f;
-       return 1;
-}
-
-static void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
+static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
 {
        handle_scancode(keycode, !up_flag);
 }
index a5c2b2bff5c3cb7446e5a3ef063ff9d32c3cb2bc..4eecd0cc1ed87303d807a4f0cc84ae7983930a57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/char/rpcmouse.c
+ * linux/drivers/char/mouse_rpc.c
  *
  * Copyright (C) 1996-1998 Russell King
  *
@@ -16,6 +16,7 @@
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/iomd.h>
 
 #include "../../char/mouse.h"
 
index 23a625658ed6b5200c27774be46a835b67b08c00..a1ea1c61f673f4adb69d63cbc25b475f101a1096 100644 (file)
 #ifdef MODULE
 static int __serial_ports[NUM_SERIALS];
 static int __serial_pcount;
+static int __serial_addr[NUM_SERIALS];
 static struct expansion_card *expcard[MAX_ECARDS];
 #define ADD_ECARD(ec,card) expcard[(card)] = (ec)
-#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port)
+#define ADD_PORT(port,addr)                                    \
+       do {                                                    \
+               __serial_ports[__serial_pcount] = (port);       \
+               __serial_addr[__serial_pcount] = (addr);        \
+               __serial_pcount += 1;                           \
+       } while (0)
 #undef MY_INIT
 #define MY_INIT init_module
 #else
 #define ADD_ECARD(ec,card)
-#define ADD_PORT(port)
+#define ADD_PORT(port,addr)
 #endif
 
 static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } };
@@ -75,12 +81,15 @@ int MY_INIT (void)
        cardaddr = MY_BASE_ADDRESS(ec);
 
        for (port = 0; port < MY_NUMPORTS; port ++) {
+           unsigned long address;
            int line;
 
-           line = serial_register_onedev (MY_PORT_ADDRESS(port, cardaddr), ec->irq);
+           address = MY_PORT_ADDRESS(port, cardaddr);
+
+           line = serial_register_onedev (address, ec->irq);
            if (line < 0)
                break;
-           ADD_PORT(line);
+           ADD_PORT(line, address);
        }
 
        if (port) {
@@ -97,8 +106,10 @@ void cleanup_module (void)
 {
     int i;
 
-    for (i = 0; i < __serial_pcount; i++)
-       unregister_serial (__serial_ports[i]);
+    for (i = 0; i < __serial_pcount; i++) {
+       unregister_serial(__serial_ports[i]);
+       release_region(__serial_addr[i], 8);
+    }
 
     for (i = 0; i < MAX_ECARDS; i++)
        if (expcard[i])
index 1d2283f3d9b1a9dc4a468c0792446b7acc4dd2f4..31e7cc0873cfadb1dc0545eabd68134c23e2b2ec 100644 (file)
@@ -71,7 +71,7 @@ static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n";
 #define BUS_16 16
 #define BUS_8  8
 
-static const card_ids ether1_cids[] = {
+static const card_ids __init ether1_cids[] = {
        { MANU_ACORN, PROD_ACORN_ETHER1 },
        { 0xffff, 0xffff }
 };
@@ -128,7 +128,7 @@ ether1_inswb (unsigned int addr, void *data, unsigned int len)
 {
        int used;
 
-       addr = IO_BASE + (addr << 2);
+       addr = ioaddr(addr);
 
        __asm__ __volatile__(
                "subs   %3, %3, #2
@@ -171,7 +171,7 @@ ether1_outswb (unsigned int addr, void *data, unsigned int len)
 {
        int used;
 
-       addr = IO_BASE + (addr << 2);
+       addr = ioaddr(addr);
 
        __asm__ __volatile__(
                "subs   %3, %3, #2
@@ -659,12 +659,6 @@ ether1_probe1 (struct device *dev))
        /* Fill in the fields of the device structure with ethernet values */
        ether_setup (dev);
 
-#ifndef CLAIM_IRQ_AT_OPEN
-       if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) {
-               kfree (dev->priv);
-               return -EAGAIN;
-       }
-#endif
        return 0;
 }      
     
@@ -759,18 +753,16 @@ static int
 ether1_open (struct device *dev)
 {
        struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-#ifdef CLAIM_IRQ_AT_OPEN
+
        if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
                return -EAGAIN;
-#endif
+
        MOD_INC_USE_COUNT;
 
        memset (&priv->stats, 0, sizeof (struct enet_statistics));
 
        if (ether1_init_for_open (dev)) {
-#ifdef CLAIM_IRQ_AT_OPEN
                free_irq (dev->irq, dev);
-#endif
                MOD_DEC_USE_COUNT;
                return -EAGAIN;
        }
@@ -1080,12 +1072,10 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 static int
 ether1_close (struct device *dev)
 {
-#ifdef CLAIM_IRQ_AT_OPEN
-       free_irq (dev->irq, dev);
-#endif
-
        ether1_reset (dev);
 
+       free_irq(dev->irq, dev);
+
        dev->start = 0;
        dev->tbusy = 0;
 
@@ -1117,56 +1107,46 @@ ether1_setmulticastlist (struct device *dev)
 
 #ifdef MODULE
 
-static char ethernames[MAX_ECARDS][9];
-static struct device *my_ethers[MAX_ECARDS];
-static struct expansion_card *ec[MAX_ECARDS];
+static struct ether_dev {
+       struct expansion_card   *ec;
+       char                    name[9];
+       struct device           dev;
+} ether_devs[MAX_ECARDS];
 
 int
 init_module (void)
 {
-       int i;
+       struct expansion_card *ec;
+       int i, ret = -ENODEV;
 
-       for (i = 0; i < MAX_ECARDS; i++) {
-               my_ethers[i] = NULL;
-               ec[i] = NULL;
-               strcpy (ethernames[i], "        ");
-       }
+       memset(ether_devs, 0, sizeof(ether_devs));
 
+       ecard_startfind ();
+       ec = ecard_find(0, ether1_cids);
        i = 0;
 
-       ecard_startfind ();
+       while (ec && i < MAX_ECARDS) {
+               ecard_claim(ec);
 
-       do {
-               if ((ec[i] = ecard_find(0, ether1_cids)) == NULL)
-                       break;
+               ether_devs[i].ec            = ec;
+               ether_devs[i].dev.irq       = ec->irq;
+               ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+               ether_devs[i].dev.init      = ether1_probe;
+               ether_devs[i].dev.name      = ether_devs[i].name;
 
-               my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL);
-               memset (my_ethers[i], 0, sizeof (struct device));
-
-               my_ethers[i]->irq = ec[i]->irq;
-               my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST);
-               my_ethers[i]->init = ether1_probe;
-               my_ethers[i]->name = ethernames[i];
-
-               ecard_claim (ec[i]);
-
-               if (register_netdev (my_ethers[i]) != 0) {
-                       for (i = 0; i < 4; i++) {
-                               if (my_ethers[i]) {
-                                       kfree (my_ethers[i]);
-                                       my_ethers[i] = NULL;
-                               }
-                               if (ec[i]) {
-                                       ecard_release (ec[i]);
-                                       ec[i] = NULL;
-                               }
-                       }
-                       return -EIO;
+               ret = register_netdev(&ether_devs[i].dev);
+
+               if (ret) {
+                       ecard_release(ec);
+                       ether_devs[i].ec = NULL;
+                       break;
                }
-               i++;
-       } while (i < MAX_ECARDS);
 
-       return i != 0 ? 0 : -ENODEV;
+               i += 1;
+               ec = ecard_find(0, ether1_cids);
+       }
+
+       return i != 0 ? 0 : ret;
 }
 
 void
@@ -1175,18 +1155,15 @@ cleanup_module (void)
        int i;
 
        for (i = 0; i < MAX_ECARDS; i++) {
-               if (my_ethers[i]) {
-                       unregister_netdev (my_ethers[i]);
-                       release_region (my_ethers[i]->base_addr, 16);
-                       release_region (my_ethers[i]->base_addr + 0x800, 4096);
-#ifndef CLAIM_IRQ_AT_OPEN
-                       free_irq (my_ethers[i]->irq, my_ethers[i]);
-#endif
-                       my_ethers[i] = NULL;
-               }
-               if (ec[i]) {
-                       ecard_release (ec[i]);
-                       ec[i] = NULL;
+               if (ether_devs[i].ec) {
+                       unregister_netdev(&ether_devs[i].dev);
+
+                       release_region(ether_devs[i].dev.base_addr, 16);
+                       release_region(ether_devs[i].dev.base_addr + 0x800, 4096);
+
+                       ecard_release(ether_devs[i].ec);
+
+                       ether_devs[i].ec = NULL;
                }
        }
 }
index ca89b7e59463195ebdf7d0b7797b259b4e418c3f..ea6c13da5f6a678ea344f381c15cc5b8b9da785b 100644 (file)
  *                             packet starts two bytes from the end of the
  *                             buffer, it corrupts the receiver chain, and
  *                             never updates the transmit status correctly.
- * TODO:
- *  When we detect a fatal error on the interface, we should restart it.
+ * 1.14        RMK     07/01/1998      Added initial code for ETHERB addressing.
+ * 1.15        RMK     30/04/1999      More fixes to the transmit routine for buggy
+ *                             hardware.
  */
 
-static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
+static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -66,7 +67,7 @@ static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
 #include "ether3.h"
 
 static unsigned int net_debug = NET_DEBUG;
-static const card_ids ether3_cids[] = {
+static const card_ids __init ether3_cids[] = {
        { MANU_ANT2, PROD_ANT_ETHER3 },
        { MANU_ANT,  PROD_ANT_ETHER3 },
        { MANU_ANT,  PROD_ANT_ETHERB }, /* trial - will etherb work? */
@@ -77,9 +78,6 @@ static void ether3_setmulticastlist(struct device *dev);
 static int  ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt);
 static void ether3_tx(struct device *dev, struct dev_priv *priv);
 
-extern int inswb(int reg, void *buffer, int len);
-extern int outswb(int reg, void *buffer, int len);
-
 #define BUS_16         2
 #define BUS_8          1
 #define BUS_UNKNOWN    0
@@ -88,7 +86,7 @@ extern int outswb(int reg, void *buffer, int len);
  * I'm not sure what address we should default to if the internal one
  * is corrupted...
  */
-unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+unsigned char def_eth_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
 
 /* --------------------------------------------------------------------------- */
 
@@ -99,6 +97,8 @@ typedef enum {
 
 /*
  * ether3 read/write.  Slow things down a bit...
+ * The SEEQ8005 doesn't like us writing to it's registers
+ * too quickly.
  */
 #define ether3_outb(v,r)       { outb((v),(r)); udelay(1); }
 #define ether3_outw(v,r)       { outw((v),(r)); udelay(1); }
@@ -138,7 +138,7 @@ ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
  * write data to the buffer memory
  */
 #define ether3_writebuffer(dev,data,length)                    \
-       outswb(REG_BUFWIN, (data), (length))
+       outsw(REG_BUFWIN, (data), (length) >> 1)
 
 #define ether3_writeword(dev,data)                             \
        outw((data), REG_BUFWIN)
@@ -153,7 +153,7 @@ ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
  * read data from the buffer memory
  */
 #define ether3_readbuffer(dev,data,length)                     \
-       inswb(REG_BUFWIN, (data), (length))
+       insw(REG_BUFWIN, (data), (length) >> 1)
 
 #define ether3_readword(dev)                                   \
        inw(REG_BUFWIN)
@@ -249,7 +249,7 @@ ether3_ramtest(struct device *dev, unsigned char byte))
                        }
                } else {
                        if (bad != -1) {
-                               if (bad != i - 1)
+                               if (bad != i - 1)
                                        printk(" - 0x%04X\n", i - 1);
                                printk("\n");
                                bad = -1;
@@ -335,7 +335,6 @@ ether3_init_for_open(struct device *dev)
        for (i = 0; i < 6; i++)
                ether3_outb(dev->dev_addr[i], REG_BUFWIN);
 
-       priv->tx_used   = 0;
        priv->tx_head   = 0;
        priv->tx_tail   = 0;
        priv->regs.config2 |= CFG2_CTRLO;
@@ -471,6 +470,25 @@ failed:
        return error;
 }
 
+__initfunc(static void
+ether3_get_dev(struct device *dev, struct expansion_card *ec))
+{
+       ecard_claim(ec);
+
+       dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+       dev->irq = ec->irq;
+
+       if (ec->cid.manufacturer == MANU_ANT &&
+           ec->cid.product == PROD_ANT_ETHERB) {
+               dev->base_addr += 0x200;
+       }
+
+       ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
+       ec->irqmask = 0xf0;
+
+       ether3_addr(dev->dev_addr, ec);
+}
+
 #ifndef MODULE
 __initfunc(int
 ether3_probe(struct device *dev))
@@ -485,12 +503,8 @@ ether3_probe(struct device *dev))
        if ((ec = ecard_find(0, ether3_cids)) == NULL)
                return ENODEV;
 
-       dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
-       dev->irq = ec->irq;
-
-       ecard_claim(ec);
+       ether3_get_dev(dev, ec);
 
-       ether3_addr(dev->dev_addr, ec);
        return ether3_probe1(dev);
 }
 #endif
@@ -580,33 +594,6 @@ static void ether3_setmulticastlist(struct device *dev)
        ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 }
 
-/*
- * Allocate memory in transmitter ring buffer.
- */
-static int
-ether3_alloc_tx(struct dev_priv *priv, int length, int alloc)
-{
-       int start, head, tail;
-
-       tail = priv->tx_tail;
-       start = priv->tx_head;
-       head = start + length + 4;
-
-       if (head >= TX_END) {
-               if (tail > priv->tx_head)
-                       return -1;
-               head -= TX_END - TX_START;
-               if (tail < head)
-                       return -1;
-       } else if (start < tail && tail < head)
-               return -1;
-
-       if (alloc)
-               priv->tx_head = head;
-
-       return start;
-}
-
 /*
  * Transmit a packet
  */
@@ -622,7 +609,7 @@ retry:
                if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
                        unsigned long flags;
                        unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-                       int ptr;
+                       unsigned int ptr, next_ptr;
 
                        length = (length + 1) & ~1;
 
@@ -633,23 +620,31 @@ retry:
                                return 0;
                        }
 
+                       next_ptr = (priv->tx_head + 1) & 15;
+
                        save_flags_cli(flags);
 
-                       ptr = ether3_alloc_tx(priv, length, 1);
-                       if (ptr == -1)
+                       if (priv->tx_tail == next_ptr) {
+                               restore_flags(flags);
                                return 1;       /* unable to queue */
+                       }
+
+                       dev->trans_start = jiffies;
+                       ptr              = 0x600 * priv->tx_head;
+                       priv->tx_head    = next_ptr;
+                       next_ptr        *= 0x600;
 
 #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
 
-                       ether3_setbuffer(dev, buffer_write, priv->tx_head);
+                       ether3_setbuffer(dev, buffer_write, next_ptr);
                        ether3_writelong(dev, 0);
-
                        ether3_setbuffer(dev, buffer_write, ptr);
                        ether3_writelong(dev, 0);
                        ether3_writebuffer(dev, skb->data, length);
-
+                       ether3_writeword(dev, htons(next_ptr));
+                       ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
                        ether3_setbuffer(dev, buffer_write, ptr);
-                       ether3_writeword(dev, htons(priv->tx_head));
+                       ether3_writeword(dev, htons((ptr + length + 4)));
                        ether3_writeword(dev, TXHDR_FLAGS >> 16);
                        ether3_ledon(dev, priv);
 
@@ -658,11 +653,10 @@ retry:
                                ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
                        }
 
-                       if (ether3_alloc_tx(priv, 2044, 0) != -1)
+                       next_ptr = (priv->tx_head + 1) & 15;
+                       if (priv->tx_tail != next_ptr)
                                dev->tbusy = 0;
 
-                       dev->trans_start = jiffies;
-
                        restore_flags(flags);
 
                        dev_kfree_skb(skb);
@@ -689,7 +683,7 @@ retry:
                        ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
                printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
                        ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
-               printk(KERN_ERR "%s: tx head=%04X tx tail=%04X\n", dev->name,
+               printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
                        priv->tx_head, priv->tx_tail);
                ether3_setbuffer(dev, buffer_read, priv->tx_tail);
                printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
@@ -698,8 +692,9 @@ retry:
                dev->tbusy = 0;
                priv->regs.config2 |= CFG2_CTRLO;
                priv->stats.tx_errors += 1;
-               ether3_outw(priv->regs.config2 , REG_CONFIG2);
+               ether3_outw(priv->regs.config2, REG_CONFIG2);
                dev->trans_start = jiffies;
+               priv->tx_head = priv->tx_tail = 0;
                goto retry;
        }
 }
@@ -867,6 +862,7 @@ static void
 ether3_tx(struct device *dev, struct dev_priv *priv)
 {
        unsigned int tx_tail = priv->tx_tail;
+       int max_work = 14;
 
        do {
                unsigned long status;
@@ -874,7 +870,7 @@ ether3_tx(struct device *dev, struct dev_priv *priv)
                /*
                 * Read the packet header
                 */
-               ether3_setbuffer(dev, buffer_read, tx_tail);
+               ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
                status = ether3_readlong(dev);
 
                /*
@@ -895,95 +891,72 @@ ether3_tx(struct device *dev, struct dev_priv *priv)
                        if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
                }
 
-               tx_tail = htons(status & TX_NEXT);
-               if (tx_tail < TX_START || tx_tail >= TX_END) {
-                       printk("%s: transmit error: next pointer = %04X\n", dev->name, tx_tail);
-                       tx_tail = TX_START;
-                       priv->tx_head = TX_START;
-                       priv->tx_tail = TX_END;
-               }
-       } while (1);
+               tx_tail = (tx_tail + 1) & 15;
+       } while (--max_work);
 
        if (priv->tx_tail != tx_tail) {
                priv->tx_tail = tx_tail;
-               if (priv->tx_used <= MAX_TX_BUFFERED) {
-                       dev->tbusy = 0;
-                       mark_bh(NET_BH);        /* Inform upper layers. */
-               }
+               dev->tbusy = 0;
+               mark_bh(NET_BH);        /* Inform upper layers. */
        }
 }
 
 #ifdef MODULE
 
-char ethernames[MAX_ECARDS][9];
-
-static struct device *my_ethers[MAX_ECARDS];
-static struct expansion_card *ec[MAX_ECARDS];
+static struct ether_dev {
+       struct expansion_card   *ec;
+       char                    name[9];
+       struct device           dev;
+} ether_devs[MAX_ECARDS];
 
 int
 init_module(void)
 {
-       int i;
+       struct expansion_card *ec;
+       int i, ret = -ENODEV;
 
-       for(i = 0; i < MAX_ECARDS; i++) {
-               my_ethers[i] = NULL;
-               ec[i] = NULL;
-               strcpy(ethernames[i], "        ");
-       }
+       memset(ether_devs, 0, sizeof(ether_devs));
 
+       ecard_startfind ();
+       ec = ecard_find(0, ether3_cids);
        i = 0;
 
-       ecard_startfind();
+       while (ec && i < MAX_ECARDS) {
+               ecard_claim(ec);
 
-       do {
-               if ((ec[i] = ecard_find(0, ether3_cids)) == NULL)
-                       break;
+               ether_devs[i].ec            = ec;
+               ether_devs[i].dev.init      = ether3_probe1;
+               ether_devs[i].dev.name      = ether_devs[i].name;
+               ether3_get_dev(&ether_devs[i].dev, ec);
 
-               my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
-               memset(my_ethers[i], 0, sizeof(struct device));
+               ret = register_netdev(&ether_devs[i].dev);
 
-               my_ethers[i]->irq = ec[i]->irq;
-               my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0);
-               my_ethers[i]->init = ether3_probe1;
-               my_ethers[i]->name = ethernames[i];
-
-               ether3_addr(my_ethers[i]->dev_addr, ec[i]);
-
-               ecard_claim(ec[i]);
+               if (ret) {
+                       ecard_release(ec);
+                       ether_devs[i].ec = NULL;
+               } else
+                       i += 1;
 
-               if(register_netdev(my_ethers[i]) != 0) {
-                       for (i = 0; i < 4; i++) {
-                               if(my_ethers[i]) {
-                                       kfree(my_ethers[i]);
-                                       my_ethers[i] = NULL;
-                               }
-                               if(ec[i]) {
-                                       ecard_release(ec[i]);
-                                       ec[i] = NULL;
-                               }
-                       }
-                       return -EIO;
-               }
-               i++;
+               ec = ecard_find(0, ether3_cids);
        }
-       while(i < MAX_ECARDS);
 
-       return i != 0 ? 0 : -ENODEV;
+       return i != 0 ? 0 : ret;
 }
 
 void
 cleanup_module(void)
 {
        int i;
+
        for (i = 0; i < MAX_ECARDS; i++) {
-               if (my_ethers[i]) {
-                       release_region(my_ethers[i]->base_addr, 128);
-                       unregister_netdev(my_ethers[i]);
-                       my_ethers[i] = NULL;
-               }
-               if (ec[i]) {
-                       ecard_release(ec[i]);
-                       ec[i] = NULL;
+               if (ether_devs[i].ec) {
+                       unregister_netdev(&ether_devs[i].dev);
+
+                       release_region(ether_devs[i].dev.base_addr, 128);
+
+                       ecard_release(ether_devs[i].ec);
+
+                       ether_devs[i].ec = NULL;
                }
        }
 }
index 2a92052a448b262ed7c088f781588f9e81292ec4..ed9f2e6f7334a14a94568a2229633af001813ab0 100644 (file)
@@ -151,9 +151,8 @@ struct dev_priv {
        unsigned int config1;
        unsigned int config2;
     } regs;
-    unsigned int tx_head;              /* address to insert next packet         */
-    unsigned int tx_tail;              /* address of transmitting packet        */
-    unsigned int tx_used;              /* number of 'slots' used                */
+    unsigned char tx_head;             /* buffer nr to insert next packet       */
+    unsigned char tx_tail;             /* buffer nr of transmitting packet      */
     unsigned int rx_head;              /* address to fetch next packet from     */
     struct enet_statistics stats;
     struct timer_list timer;
index 4f88f6bb4696af89465566c099d245d0d819aa19..319b66cfc227456e1f155d6abde4f1ba992369e7 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
 #define DEBUG_INIT 2
 
 static unsigned int net_debug = NET_DEBUG;
-static const card_ids etherh_cids[] = {
+static const card_ids __init etherh_cids[] = {
        { MANU_I3, PROD_I3_ETHERLAN500 },
        { MANU_I3, PROD_I3_ETHERLAN600 },
        { MANU_I3, PROD_I3_ETHERLAN600A },
        { 0xffff, 0xffff }
 };
 
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("i3 EtherH driver");
+
 static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n";
 
 #define ETHERH500_DATAPORT     0x200   /* MEMC */
@@ -80,8 +84,8 @@ static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King
  * Read the ethernet address string from the on board rom.
  * This is an ascii string...
  */
-static int
-etherh_addr(char *addr, struct expansion_card *ec)
+__initfunc(static int
+etherh_addr(char *addr, struct expansion_card *ec))
 {
        struct in_chunk_dir cd;
        char *s;
@@ -216,10 +220,8 @@ etherh_block_output (struct device *dev, int count, const unsigned char *buf, in
 
        if (ei_status.word16)
                outsw (dma_addr, buf, count >> 1);
-#ifdef BIT8
        else
                outsb (dma_addr, buf, count);
-#endif
 
        dma_start = jiffies;
 
@@ -268,11 +270,8 @@ etherh_block_input (struct device *dev, int count, struct sk_buff *skb, int ring
                insw (dma_addr, buf, count >> 1);
                if (count & 1)
                        buf[count - 1] = inb (dma_addr);
-       }
-#ifdef BIT8
-       else
+       } else
                insb (dma_addr, buf, count);
-#endif
 
        outb (ENISR_RDC, addr + EN0_ISR);
        ei_status.dmaing &= ~1;
@@ -307,10 +306,8 @@ etherh_get_header (struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 
        if (ei_status.word16)
                insw (dma_addr, hdr, sizeof (*hdr) >> 1);
-#ifdef BIT8
        else
                insb (dma_addr, hdr, sizeof (*hdr));
-#endif
 
        outb (ENISR_RDC, addr + EN0_ISR);
        ei_status.dmaing &= ~1;
@@ -355,8 +352,8 @@ etherh_close(struct device *dev)
 /*
  * This is the real probe routine.
  */
-static int
-etherh_probe1(struct device *dev)
+__initfunc(static int
+etherh_probe1(struct device *dev))
 {
        static int version_printed;
        unsigned int addr, i, reg0, tmp;
@@ -461,10 +458,13 @@ static expansioncard_ops_t etherh_ops = {
        etherh_irq_enable,
        etherh_irq_disable,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
-static void etherh_initdev (ecard_t *ec, struct device *dev)
+__initfunc(static void
+etherh_initdev(ecard_t *ec, struct device *dev))
 {
        ecard_claim (ec);
        
@@ -492,27 +492,27 @@ static void etherh_initdev (ecard_t *ec, struct device *dev)
        }
        ec->ops = &etherh_ops;
 
-       etherh_addr (dev->dev_addr, ec);
+       etherh_addr(dev->dev_addr, ec);
 }
 
 #ifndef MODULE
-int
-etherh_probe(struct device *dev)
+__initfunc(int
+etherh_probe(struct device *dev))
 {
        if (!dev)
                return ENODEV;
 
-       ecard_startfind ();
-
-       if (!dev->base_addr) {
+       if (!dev->base_addr || dev->base_addr == 0xffe0) {
                struct expansion_card *ec;
 
+               ecard_startfind();
+
                if ((ec = ecard_find (0, etherh_cids)) == NULL)
                        return ENODEV;
 
-               etherh_initdev (ec, dev);
+               etherh_initdev(ec, dev);
        }
-       return etherh_probe1 (dev);
+       return etherh_probe1(dev);
 }
 #endif
 
@@ -529,12 +529,10 @@ static int
 init_all_cards(void)
 {
        struct device *dev = NULL;
-       struct expansion_card *boguscards[MAX_ETHERH_CARDS];
        int i, found = 0;
 
        for (i = 0; i < MAX_ETHERH_CARDS; i++) {
                my_ethers[i] = NULL;
-               boguscards[i] = NULL;
                ec[i] = NULL;
                strcpy (ethernames[i], "        ");
        }
@@ -571,7 +569,7 @@ init_all_cards(void)
                if (register_netdev(dev) != 0) {
                        printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr);
                        if (ec[i]) {
-                               boguscards[i] = ec[i];
+                               ecard_release(ec[i]);
                                ec[i] = NULL;
                        }
                        continue;
@@ -583,12 +581,6 @@ init_all_cards(void)
        if (dev)
                kfree (dev);
 
-       for (i = 0; i < MAX_ETHERH_CARDS; i++)
-               if (boguscards[i]) {
-                       boguscards[i]->ops = NULL;
-                       ecard_release (boguscards[i]);
-               }
-
        return found ? 0 : -ENODEV;
 }
 
index 5b8d14429965e1318c606871ff5199dc1450dac7..68d4f920bf51aa528a502657f07d2dd4ac55efca 100644 (file)
@@ -7,11 +7,12 @@ if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then
   bool '  Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
   dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
   dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
   dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
 
-  comment 'The following drives are not fully supported'
+  comment 'The following drivers are not fully supported'
 
   dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
   if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
index f6963853017ec2b223816b2e89bbff525e15dcb7..6efd2268176481431d9289e9c0e8812cb6743500 100644 (file)
@@ -24,6 +24,16 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_ARXESCSI),y)
+  L_OBJS += arxescsi.o
+  CONFIG_FAS216_BUILTIN=y
+else
+  ifeq ($(CONFIG_SCSI_ARXESCSI),m)
+    M_OBJS += arxescsi.o
+    CONFIG_FAS216_MODULE=y
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_CUMANA_1),y)
   L_OBJS += cumana_1.o
 else
@@ -34,12 +44,10 @@ endif
 
 ifeq ($(CONFIG_SCSI_CUMANA_2),y)
   L_OBJS += cumana_2.o
-  CONFIG_QUEUE_BUILTIN=y
   CONFIG_FAS216_BUILTIN=y
 else
   ifeq ($(CONFIG_SCSI_CUMANA_2),m)
     M_OBJS += cumana_2.o
-    CONFIG_QUEUE_MODULE=y
     CONFIG_FAS216_MODULE=y
   endif
 endif
@@ -62,41 +70,39 @@ endif
 
 ifeq ($(CONFIG_SCSI_POWERTECSCSI),y)
   L_OBJS += powertec.o
-  CONFIG_QUEUE_BUILTIN=y
   CONFIG_FAS216_BUILTIN=y
 else
   ifeq ($(CONFIG_SCSI_POWERTECSCSI),m)
     M_OBJS += powertec.o
-    CONFIG_QUEUE_MODULE=y
     CONFIG_FAS216_MODULE=y
   endif
 endif
 
 ifeq ($(CONFIG_SCSI_EESOXSCSI),y)
   L_OBJS += eesox.o
-  CONFIG_QUEUE_BUILTIN=y
   CONFIG_FAS216_BUILTIN=y
 else
   ifeq ($(CONFIG_SCSI_EESOXSCSI),m)
     M_OBJS += eesox.o
-    CONFIG_QUEUE_MODULE=y
     CONFIG_FAS216_MODULE=y
   endif
 endif
 
-ifeq ($(CONFIG_QUEUE_BUILTIN),y)
-  LX_OBJS += queue.o msgqueue.o
-else
-  ifeq ($(CONFIG_QUEUE_MODULE),y)
-    MX_OBJS += queue.o msgqueue.o
-  endif
-endif
-
 ifeq ($(CONFIG_FAS216_BUILTIN),y)
   LX_OBJS += fas216.o
+  CONFIG_QUEUE_BUILTIN=y
 else
   ifeq ($(CONFIG_FAS216_MODULE),y)
     MX_OBJS += fas216.o
+    CONFIG_QUEUE_MODULE=y
+  endif
+endif
+
+ifeq ($(CONFIG_QUEUE_BUILTIN),y)
+  LX_OBJS += queue.o msgqueue.o
+else
+  ifeq ($(CONFIG_QUEUE_MODULE),y)
+    MX_OBJS += queue.o msgqueue.o
   endif
 endif
 
index 50ec36436b7a2785d6c66e79579a2da7d28979b0..1e83bbead353e44bbb95811a2a6d6e7f6711af05 100644 (file)
@@ -21,6 +21,8 @@
  *  12-Oct-1997        RMK     Added catch for re-entering interrupt routine.
  *  15-Oct-1997        RMK     Improved handling of commands.
  *  27-Jun-1998        RMK     Changed asm/delay.h to linux/delay.h.
+ *  13-Dec-1998        RMK     Better abort code and command handling.  Extra state
+ *                     transitions added to allow dodgy devices to work.
  */
 #define DEBUG_NO_WRITE 1
 #define DEBUG_QUEUES   2
@@ -35,7 +37,7 @@
 #define DEBUG_RESET    1024
 #define DEBUG_ALL      (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
                         DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
-                        DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE)
+                        DEBUG_DMA|DEBUG_QUEUES)
 
 /* DRIVER CONFIGURATION
  *
 #ifndef STRINGIFY
 #define STRINGIFY(x) #x
 #endif
-#define STR(x) STRINGIFY(x)
-#define NO_WRITE_STR STR(NO_WRITE)
+#define STRx(x) STRINGIFY(x)
+#define NO_WRITE_STR STRx(NO_WRITE)
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/ecard.h>
 
 #include "../../scsi/scsi.h"
 #error "Yippee!  ABORT TAG is now defined!  Remove this error!"
 #endif
 
-#ifndef NO_IRQ
-#define NO_IRQ 255
-#endif
-
 #ifdef CONFIG_SCSI_ACORNSCSI_LINK
 #error SCSI2 LINKed commands not supported (yet)!
 #endif
 #define DMAC_BUFFER_SIZE       65536
 #endif
 
-/*
- * This is used to dump the previous states of the SBIC
- */
-static struct status_entry {
-       unsigned long   when;
-       unsigned char   ssr;
-       unsigned char   ph;
-       unsigned char   irq;
-       unsigned char   unused;
-} status[9][16];
-static unsigned char status_ptr[9];
-
-#define ADD_STATUS(_q,_ssr,_ph,_irq) \
-({                                                     \
-       status[(_q)][status_ptr[(_q)]].when = jiffies;  \
-       status[(_q)][status_ptr[(_q)]].ssr  = (_ssr);   \
-       status[(_q)][status_ptr[(_q)]].ph   = (_ph);    \
-       status[(_q)][status_ptr[(_q)]].irq  = (_irq);   \
-       status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \
-})
+#define STATUS_BUFFER_TO_PRINT 24
 
 unsigned int sdtr_period = SDTR_PERIOD;
 unsigned int sdtr_size   = SDTR_SIZE;
@@ -214,31 +194,31 @@ static struct proc_dir_entry proc_scsi_acornscsi = {
        PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
-static int acornscsi_reconnect_finish (AS_Host *host);
-static void acornscsi_dma_cleanup (AS_Host *host);
-static void acornscsi_abortcmd (AS_Host *host, unsigned char tag);
+static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static int acornscsi_reconnect_finish(AS_Host *host);
+static void acornscsi_dma_cleanup(AS_Host *host);
+static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
 
 /* ====================================================================================
  * Miscellaneous
  */
 
 static inline void
-sbic_arm_write (unsigned int io_port, int reg, int value)
+sbic_arm_write(unsigned int io_port, int reg, int value)
 {
-    outb_t (reg, io_port);
-    outb_t (value, io_port + 4);
+    outb_t(reg, io_port);
+    outb_t(value, io_port + 4);
 }
 
 #define sbic_arm_writenext(io,val) \
-       outb_t ((val), (io) + 4)
+       outb_t((val), (io) + 4)
 
 static inline
-int sbic_arm_read (unsigned int io_port, int reg)
+int sbic_arm_read(unsigned int io_port, int reg)
 {
     if(reg == ASR)
           return inl_t(io_port) & 255;
-    outb_t (reg, io_port);
+    outb_t(reg, io_port);
     return inl_t(io_port + 4) & 255;
 }
 
@@ -247,129 +227,165 @@ int sbic_arm_read (unsigned int io_port, int reg)
 
 #ifdef USE_DMAC
 #define dmac_read(io_port,reg) \
-       inb ((io_port) + (reg))
+       inb((io_port) + (reg))
 
 #define dmac_write(io_port,reg,value) \
-       ({ outb ((value), (io_port) + (reg)); })
+       ({ outb((value), (io_port) + (reg)); })
 
 #define dmac_clearintr(io_port) \
-       ({ outb (0, (io_port)); })
+       ({ outb(0, (io_port)); })
 
 static inline
-unsigned int dmac_address (unsigned int io_port)
+unsigned int dmac_address(unsigned int io_port)
 {
-    return dmac_read (io_port, TXADRHI) << 16 |
-          dmac_read (io_port, TXADRMD) << 8 |
-          dmac_read (io_port, TXADRLO);
+    return dmac_read(io_port, TXADRHI) << 16 |
+          dmac_read(io_port, TXADRMD) << 8 |
+          dmac_read(io_port, TXADRLO);
 }
 
 static
-void acornscsi_dumpdma (AS_Host *host, char *where)
+void acornscsi_dumpdma(AS_Host *host, char *where)
 {
        unsigned int mode, addr, len;
 
-       mode = dmac_read (host->dma.io_port, MODECON);
-       addr = dmac_address (host->dma.io_port);
-       len  = dmac_read (host->dma.io_port, TXCNTHI) << 8 |
-              dmac_read (host->dma.io_port, TXCNTLO);
+       mode = dmac_read(host->dma.io_port, MODECON);
+       addr = dmac_address(host->dma.io_port);
+       len  = dmac_read(host->dma.io_port, TXCNTHI) << 8 |
+              dmac_read(host->dma.io_port, TXCNTLO);
 
-       printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
+       printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
                host->host->host_no, where,
                mode, addr, (len + 1) & 0xffff,
-               dmac_read (host->dma.io_port, MASKREG));
+               dmac_read(host->dma.io_port, MASKREG));
 
-       printk ("DMA @%06x, ", host->dma.start_addr);
-       printk ("BH @%p +%04x, ", host->scsi.SCp.ptr,
+       printk("DMA @%06x, ", host->dma.start_addr);
+       printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
                host->scsi.SCp.this_residual);
-       printk ("DT @+%04x ST @+%04x", host->dma.transferred,
+       printk("DT @+%04x ST @+%04x", host->dma.transferred,
                host->scsi.SCp.scsi_xferred);
-       printk ("\n");
+       printk("\n");
 }
 #endif
 
 static
-unsigned long acornscsi_sbic_xfcount (AS_Host *host)
+unsigned long acornscsi_sbic_xfcount(AS_Host *host)
 {
     unsigned long length;
 
-    length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16;
-    length |= sbic_arm_readnext (host->scsi.io_port) << 8;
-    length |= sbic_arm_readnext (host->scsi.io_port);
+    length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16;
+    length |= sbic_arm_readnext(host->scsi.io_port) << 8;
+    length |= sbic_arm_readnext(host->scsi.io_port);
 
     return length;
 }
 
-static
-int acornscsi_sbic_issuecmd (AS_Host *host, int command)
+static int
+acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
 {
-    int asr;
+       int asr;
 
-    do {
-       asr = sbic_arm_read (host->scsi.io_port, ASR);
-    } while (asr & ASR_CIP);
+       do {
+               asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+               if ((asr & stat_mask) == stat)
+                       return 0;
+
+               udelay(1);
+       } while (--timeout);
+
+       printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
+
+       return -1;
+}
 
-    sbic_arm_write (host->scsi.io_port, CMND, command);
+static
+int acornscsi_sbic_issuecmd(AS_Host *host, int command)
+{
+    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
+       return -1;
+
+    sbic_arm_write(host->scsi.io_port, CMND, command);
 
     return 0;
 }
 
 static void
-acornscsi_csdelay (unsigned int cs)
+acornscsi_csdelay(unsigned int cs)
 {
     unsigned long target_jiffies, flags;
 
     target_jiffies = jiffies + 1 + cs * HZ / 100;
 
-    save_flags (flags);
-    sti ();
+    save_flags(flags);
+    sti();
 
     while (time_before(jiffies, target_jiffies)) barrier();
 
-    restore_flags (flags);
+    restore_flags(flags);
 }
 
 static
-void acornscsi_resetcard (AS_Host *host)
+void acornscsi_resetcard(AS_Host *host)
 {
-    unsigned int i;
+    unsigned int i, timeout;
 
     /* assert reset line */
     host->card.page_reg = 0x80;
-    outb (host->card.page_reg, host->card.io_page);
+    outb(host->card.page_reg, host->card.io_page);
 
     /* wait 3 cs.  SCSI standard says 25ms. */
-    acornscsi_csdelay (3);
+    acornscsi_csdelay(3);
 
     host->card.page_reg = 0;
-    outb (host->card.page_reg, host->card.io_page);
+    outb(host->card.page_reg, host->card.io_page);
 
     /*
      * Should get a reset from the card
      */
-    while (!(inb (host->card.io_intr) & 8));
-    sbic_arm_read (host->scsi.io_port, ASR);
-    sbic_arm_read (host->scsi.io_port, SSR);
+    timeout = 1000;
+    do {
+       if (inb(host->card.io_intr) & 8)
+           break;
+       udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+       printk("scsi%d: timeout while resetting card\n",
+               host->host->host_no);
+
+    sbic_arm_read(host->scsi.io_port, ASR);
+    sbic_arm_read(host->scsi.io_port, SSR);
 
     /* setup sbic - WD33C93A */
-    sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
-    sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET);
+    sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+    sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
 
     /*
      * Command should cause a reset interrupt
      */
-    while (!(inb (host->card.io_intr) & 8));
-    sbic_arm_read (host->scsi.io_port, ASR);
-    if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01)
-       printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+    timeout = 1000;
+    do {
+       if (inb(host->card.io_intr) & 8)
+           break;
+       udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+       printk("scsi%d: timeout while resetting card\n",
                host->host->host_no);
 
-    sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
-    sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
-    sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
-    sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+    sbic_arm_read(host->scsi.io_port, ASR);
+    if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01)
+       printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+               host->host->host_no);
+
+    sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+    sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
 
     host->card.page_reg = 0x40;
-    outb (host->card.page_reg, host->card.io_page);
+    outb(host->card.page_reg, host->card.io_page);
 
     /* setup dmac - uPC71071 */
     dmac_write(host->dma.io_port, INIT, 0);
@@ -391,7 +407,7 @@ void acornscsi_resetcard (AS_Host *host)
     }
 
     /* wait 25 cs.  SCSI standard says 250ms. */
-    acornscsi_csdelay (25);
+    acornscsi_csdelay(25);
 }
 
 /*=============================================================================================
@@ -461,80 +477,101 @@ static char *acornscsi_interruptcode[] = {
 };
 
 static
-void print_scsi_status (unsigned int ssr)
+void print_scsi_status(unsigned int ssr)
 {
     if (acornscsi_map[ssr] != -1)
-       printk ("%s:%s",
+       printk("%s:%s",
                acornscsi_interrupttype[(ssr >> 4)],
                acornscsi_interruptcode[acornscsi_map[ssr]]);
     else
-       printk ("%X:%X", ssr >> 4, ssr & 0x0f);    
+       printk("%X:%X", ssr >> 4, ssr & 0x0f);    
 }    
 #endif
 
 static
-void print_sbic_status (int asr, int ssr, int cmdphase)
+void print_sbic_status(int asr, int ssr, int cmdphase)
 {
 #ifdef CONFIG_ACORNSCSI_CONSTANTS
-    printk ("sbic: %c%c%c%c%c%c ",
+    printk("sbic: %c%c%c%c%c%c ",
            asr & ASR_INT ? 'I' : 'i',
            asr & ASR_LCI ? 'L' : 'l',
            asr & ASR_BSY ? 'B' : 'b',
            asr & ASR_CIP ? 'C' : 'c',
            asr & ASR_PE  ? 'P' : 'p',
            asr & ASR_DBR ? 'D' : 'd');
-    printk ("scsi: ");
-    print_scsi_status (ssr);
-    printk (" ph %02X\n", cmdphase);
+    printk("scsi: ");
+    print_scsi_status(ssr);
+    printk(" ph %02X\n", cmdphase);
 #else
-    printk ("sbic: %02X scsi: %X:%X ph: %02X\n",
+    printk("sbic: %02X scsi: %X:%X ph: %02X\n",
            asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
 #endif
 }
 
-static
-void acornscsi_dumplog (AS_Host *host, int target)
+static void
+acornscsi_dumplogline(AS_Host *host, int target, int line)
 {
-    unsigned int prev;
-    do {
-       signed int statptr;
-
-       printk ("%c:", target == 8 ? 'H' : ('0' + target));
-       statptr = status_ptr[target] - 10;
+       unsigned long prev;
+       signed int ptr;
+
+       ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
+       if (ptr < 0)
+               ptr += STATUS_BUFFER_SIZE;
+
+       printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
+               line == 0 ? "ph" : line == 1 ? "ssr" : "int");
+
+       prev = host->status[target][ptr].when;
+
+       for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+               unsigned long time_diff;
+
+               if (!host->status[target][ptr].when)
+                       continue;
+
+               switch (line) {
+               case 0:
+                       printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
+                                        host->status[target][ptr].ph);
+                       break;
+
+               case 1:
+                       printk(" %02X", host->status[target][ptr].ssr);
+                       break;
+
+               case 2:
+                       time_diff = host->status[target][ptr].when - prev;
+                       prev = host->status[target][ptr].when;
+                       if (time_diff == 0)
+                               printk("==^");
+                       else if (time_diff >= 100)
+                               printk("   ");
+                       else
+                               printk(" %02ld", time_diff);
+                       break;
+               }
+       }
 
-       if (statptr < 0)
-           statptr += 16;
+       printk("\n");
+}
 
-       prev = status[target][statptr].when;
+static
+void acornscsi_dumplog(AS_Host *host, int target)
+{
+    do {
+       acornscsi_dumplogline(host, target, 0);
+       acornscsi_dumplogline(host, target, 1);
+       acornscsi_dumplogline(host, target, 2);
 
-       for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) {
-           if (status[target][statptr].when) {
-#ifdef CONFIG_ACORNSCSI_CONSTANTS
-               printk ("%c%02X:S=",
-                       status[target][statptr].irq ? '-' : ' ',
-                       status[target][statptr].ph);
-               print_scsi_status (status[target][statptr].ssr);
-#else
-               printk ("%c%02X:%02X",
-                       status[target][statptr].irq ? '-' : ' ',
-                       status[target][statptr].ph,
-                       status[target][statptr].ssr);
-#endif
-               printk ("+%02ld",
-                       (status[target][statptr].when - prev) < 100 ?
-                               (status[target][statptr].when - prev) : 99);
-               prev = status[target][statptr].when;
-           }
-       }
-       printk ("\n");
        if (target == 8)
            break;
+
        target = 8;
     } while (1);
 }
 
 static
-char acornscsi_target (AS_Host *host)
+char acornscsi_target(AS_Host *host)
 {
        if (host->SCpnt)
                return '0' + host->SCpnt->target;
@@ -542,7 +579,7 @@ char acornscsi_target (AS_Host *host)
 }
 
 /*
- * Prototype: cmdtype_t acornscsi_cmdtype (int command)
+ * Prototype: cmdtype_t acornscsi_cmdtype(int command)
  * Purpose  : differentiate READ from WRITE from other commands
  * Params   : command - command to interpret
  * Returns  : CMD_READ - command reads data,
@@ -550,7 +587,7 @@ char acornscsi_target (AS_Host *host)
  *           CMD_MISC  - everything else
  */
 static inline
-cmdtype_t acornscsi_cmdtype (int command)
+cmdtype_t acornscsi_cmdtype(int command)
 {
     switch (command) {
     case WRITE_6:  case WRITE_10:  case WRITE_12:
@@ -563,7 +600,7 @@ cmdtype_t acornscsi_cmdtype (int command)
 }
 
 /*
- * Prototype: int acornscsi_datadirection (int command)
+ * Prototype: int acornscsi_datadirection(int command)
  * Purpose  : differentiate between commands that have a DATA IN phase
  *           and a DATA OUT phase
  * Params   : command - command to interpret
@@ -571,7 +608,7 @@ cmdtype_t acornscsi_cmdtype (int command)
  *           DATADIR_IN  - data in phase expected
  */
 static
-datadir_t acornscsi_datadirection (int command)
+datadir_t acornscsi_datadirection(int command)
 {
     switch (command) {
     case CHANGE_DEFINITION:    case COMPARE:           case COPY:
@@ -605,13 +642,13 @@ static struct sync_xfer_tbl {
 };
 
 /*
- * Prototype: int acornscsi_getperiod (unsigned char syncxfer)
+ * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
  * Purpose  : period for the synchronous transfer setting
  * Params   : syncxfer SYNCXFER register value
  * Returns  : period in ns.
  */
 static
-int acornscsi_getperiod (unsigned char syncxfer)
+int acornscsi_getperiod(unsigned char syncxfer)
 {
     int i;
 
@@ -626,14 +663,14 @@ int acornscsi_getperiod (unsigned char syncxfer)
 }
 
 /*
- * Prototype: int round_period (unsigned int period)
+ * Prototype: int round_period(unsigned int period)
  * Purpose  : return index into above table for a required REQ period
  * Params   : period - time (ns) for REQ
  * Returns  : table index
  * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
  */
 static inline
-int round_period (unsigned int period)
+int round_period(unsigned int period)
 {
     int i;
 
@@ -646,7 +683,7 @@ int round_period (unsigned int period)
 }
 
 /*
- * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
+ * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
  * Purpose  : calculate value for 33c93s SYNC register
  * Params   : period - time (ns) for REQ
  *           offset - offset in bytes between REQ/ACK
@@ -654,7 +691,7 @@ int round_period (unsigned int period)
  * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
  */
 static
-unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
+unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
 {
     return sync_xfer_table[round_period(period)].reg_value |
                ((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
@@ -664,14 +701,14 @@ unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
  * Command functions
  */
 /*
- * Function: acornscsi_kick (AS_Host *host)
+ * Function: acornscsi_kick(AS_Host *host)
  * Purpose : kick next command to interface
  * Params  : host - host to send command to
  * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
  * Notes   : interrupts are always disabled!
  */
 static
-intr_ret_t acornscsi_kick (AS_Host *host)
+intr_ret_t acornscsi_kick(AS_Host *host)
 {
     int from_queue = 0;
     Scsi_Cmnd *SCpnt;
@@ -682,7 +719,7 @@ intr_ret_t acornscsi_kick (AS_Host *host)
 
     /* retrieve next command */
     if (!SCpnt) {
-       SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns);
+       SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
        if (!SCpnt)
            return INTR_IDLE;
 
@@ -690,11 +727,11 @@ intr_ret_t acornscsi_kick (AS_Host *host)
     }
 
     if (host->scsi.disconnectable && host->SCpnt) {
-       queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt);
+       queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
        host->scsi.disconnectable = 0;
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-       DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n",
-               host->host->host_no, acornscsi_target (host)));
+       DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
+               host->host->host_no, acornscsi_target(host)));
 #endif
        host->SCpnt = NULL;
     }
@@ -703,9 +740,9 @@ intr_ret_t acornscsi_kick (AS_Host *host)
      * If we have an interrupt pending, then we may have been reselected.
      * In this case, we don't want to write to the registers
      */
-    if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
-       sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target);
-       sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN);
+    if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
+       sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target);
+       sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN);
     }
 
     /*
@@ -717,9 +754,10 @@ intr_ret_t acornscsi_kick (AS_Host *host)
     host->scsi.SCp = SCpnt->SCp;
     host->dma.xfer_setup = 0;
     host->dma.xfer_required = 0;
+    host->dma.xfer_done = 0;
 
 #if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
-    DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n",
+    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
            host->host->host_no, '0' + SCpnt->target,
            SCpnt->cmnd[0]));
 #endif
@@ -736,11 +774,11 @@ intr_ret_t acornscsi_kick (AS_Host *host)
            SCpnt->tag = SCpnt->device->current_tag;
        } else
 #endif
-           set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+           set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
 
        host->stats.removes += 1;
 
-       switch (acornscsi_cmdtype (SCpnt->cmnd[0])) {
+       switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
        case CMD_WRITE:
            host->stats.writes += 1;
            break;
@@ -757,25 +795,25 @@ intr_ret_t acornscsi_kick (AS_Host *host)
 }    
 
 /*
- * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
  * Purpose : complete processing for command
  * Params  : host   - interface that completed
  *          result - driver byte of result
  */
 static
-void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
 {
     Scsi_Cmnd *SCpnt = *SCpntp;
 
     /* clean up */
-    sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
 
     host->stats.fins += 1;
 
     if (SCpnt) {
        *SCpntp = NULL;
 
-       acornscsi_dma_cleanup (host);
+       acornscsi_dma_cleanup(host);
 
        SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
 
@@ -787,35 +825,63 @@ void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
         * It doesn't appear to be set to something meaningful by the higher
         * levels all the time.
         */
-       if (host->scsi.SCp.ptr && result == DID_OK &&
-               acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) {
-           switch (status_byte (SCpnt->result)) {
-           case CHECK_CONDITION:
-           case COMMAND_TERMINATED:
-           case BUSY:
-           case QUEUE_FULL:
-           case RESERVATION_CONFLICT:
-               break;
-
-           default:
-               printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
-                       host->host->host_no, SCpnt->result);
-               print_command (SCpnt->cmnd);
-               acornscsi_dumpdma (host, "done");
-               acornscsi_dumplog (host, SCpnt->target);
-               SCpnt->result &= 0xffff;
-               SCpnt->result |= DID_ERROR << 16;
-           }
+       if (result == DID_OK) {
+               int xfer_warn = 0;
+
+               if (SCpnt->underflow == 0) {
+                       if (host->scsi.SCp.ptr &&
+                           acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
+                               xfer_warn = 1;
+               } else {
+                       if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
+                           host->scsi.SCp.scsi_xferred != host->dma.transferred)
+                               xfer_warn = 1;
+               }
+
+               /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
+                *  Targets which break data transfers into multiple
+                *  connections shall end each successful connection
+                *  (except possibly the last) with a SAVE DATA
+                *  POINTER - DISCONNECT message sequence.
+                *
+                * This makes it difficult to ensure that a transfer has
+                * completed.  If we reach the end of a transfer during
+                * the command, then we can only have finished the transfer.
+                * therefore, if we seem to have some data remaining, this
+                * is not a problem.
+                */
+               if (host->dma.xfer_done)
+                       xfer_warn = 0;
+
+               if (xfer_warn) {
+                   switch (status_byte(SCpnt->result)) {
+                   case CHECK_CONDITION:
+                   case COMMAND_TERMINATED:
+                   case BUSY:
+                   case QUEUE_FULL:
+                   case RESERVATION_CONFLICT:
+                       break;
+
+                   default:
+                       printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
+                               host->host->host_no, SCpnt->result);
+                       print_command(SCpnt->cmnd);
+                       acornscsi_dumpdma(host, "done");
+                       acornscsi_dumplog(host, SCpnt->target);
+                       SCpnt->result &= 0xffff;
+                       SCpnt->result |= DID_ERROR << 16;
+                   }
+               }
        }
 
        if (!SCpnt->scsi_done)
-           panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
+           panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
 
-       clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+       clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
 
-       SCpnt->scsi_done (SCpnt);
+       SCpnt->scsi_done(SCpnt);
     } else
-       printk ("scsi%d: null command in acornscsi_done", host->host->host_no);
+       printk("scsi%d: null command in acornscsi_done", host->host->host_no);
 
     host->scsi.phase = PHASE_IDLE;
 }
@@ -828,7 +894,7 @@ void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
  * Notes    : this will only be one SG entry or less
  */
 static
-void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
+void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
 {
     SCp->ptr += length;
     SCp->this_residual -= length;
@@ -839,13 +905,15 @@ void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int le
            SCp->buffers_residual--;
            SCp->ptr = (char *)SCp->buffer->address;
            SCp->this_residual = SCp->buffer->length;
-       } else
+       } else {
            SCp->ptr = NULL;
+           host->dma.xfer_done = 1;
+       }
     }
 }
 
 /*
- * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr,
+ * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
  *                             unsigned int start_addr, unsigned int length)
  * Purpose  : read data from DMA RAM
  * Params   : host - host to transfer from
@@ -855,16 +923,16 @@ void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int le
  * Notes    : this will only be one SG entry or less
  */
 static
-void acornscsi_data_read (AS_Host *host, char *ptr,
+void acornscsi_data_read(AS_Host *host, char *ptr,
                                 unsigned int start_addr, unsigned int length)
 {
-    extern void __acornscsi_in (int port, char *buf, int len);
+    extern void __acornscsi_in(int port, char *buf, int len);
     unsigned int page, offset, len = length;
 
     page = (start_addr >> 12);
     offset = start_addr & ((1 << 12) - 1);
 
-    outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
 
     while (len > 0) {
        unsigned int this_len;
@@ -874,7 +942,7 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
        else
            this_len = len;
 
-       __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len);
+       __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
 
        offset += this_len;
        ptr += this_len;
@@ -883,14 +951,14 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
        if (offset == (1 << 12)) {
            offset = 0;
            page ++;
-           outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+           outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
        }
     }
-    outb (host->card.page_reg, host->card.io_page);
+    outb(host->card.page_reg, host->card.io_page);
 }
 
 /*
- * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr,
+ * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
  *                             unsigned int start_addr, unsigned int length)
  * Purpose  : write data to DMA RAM
  * Params   : host - host to transfer from
@@ -900,16 +968,16 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
  * Notes    : this will only be one SG entry or less
  */
 static
-void acornscsi_data_write (AS_Host *host, char *ptr,
+void acornscsi_data_write(AS_Host *host, char *ptr,
                                 unsigned int start_addr, unsigned int length)
 {
-    extern void __acornscsi_out (int port, char *buf, int len);
+    extern void __acornscsi_out(int port, char *buf, int len);
     unsigned int page, offset, len = length;
 
     page = (start_addr >> 12);
     offset = start_addr & ((1 << 12) - 1);
 
-    outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
 
     while (len > 0) {
        unsigned int this_len;
@@ -919,7 +987,7 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
        else
            this_len = len;
 
-       __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len);
+       __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
 
        offset += this_len;
        ptr += this_len;
@@ -928,10 +996,10 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
        if (offset == (1 << 12)) {
            offset = 0;
            page ++;
-           outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+           outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
        }
     }
-    outb (host->card.page_reg, host->card.io_page);
+    outb(host->card.page_reg, host->card.io_page);
 }
 
 /* =========================================================================================
@@ -939,25 +1007,25 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
  */
 #ifdef USE_DMAC
 /*
- * Prototype: void acornscsi_dmastop (AS_Host *host)
+ * Prototype: void acornscsi_dmastop(AS_Host *host)
  * Purpose  : stop all DMA
  * Params   : host - host on which to stop DMA
  * Notes    : This is called when leaving DATA IN/OUT phase,
  *           or when interface is RESET
  */
 static inline
-void acornscsi_dma_stop (AS_Host *host)
+void acornscsi_dma_stop(AS_Host *host)
 {
-    dmac_write (host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr (host->dma.io_intr_clear);
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
 
 #if (DEBUG & DEBUG_DMA)
-    DBG(host->SCpnt, acornscsi_dumpdma (host, "stop"));
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
 #endif
 }
 
 /*
- * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
+ * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
  * Purpose : setup DMA controller for data transfer
  * Params  : host - host to setup
  *          direction - data transfer direction
@@ -965,19 +1033,19 @@ void acornscsi_dma_stop (AS_Host *host)
  *          while we're in a DATA I/O phase
  */
 static
-void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
+void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
 {
     unsigned int address, length, mode;
 
     host->dma.direction = direction;
 
-    dmac_write (host->dma.io_port, MASKREG, MASK_ON);
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
 
     if (direction == DMA_OUT) {
 #if (DEBUG & DEBUG_NO_WRITE)
        if (NO_WRITE & (1 << host->SCpnt->target)) {
-           printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
-                   host->host->host_no, acornscsi_target (host));
+           printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
+                   host->host->host_no, acornscsi_target(host));
            return;
        }
 #endif
@@ -988,7 +1056,7 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
     /*
      * Allocate some buffer space, limited to half the buffer size
      */
-    length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
     if (length) {
        host->dma.start_addr = address = host->dma.free_addr;
        host->dma.free_addr = (host->dma.free_addr + length) &
@@ -998,27 +1066,27 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
         * Transfer data to DMA memory
         */
        if (direction == DMA_OUT)
-           acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr,
+           acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
                                length);
 
        length -= 1;
-       dmac_write (host->dma.io_port, TXCNTLO, length);
-       dmac_write (host->dma.io_port, TXCNTHI, length >> 8);
-       dmac_write (host->dma.io_port, TXADRLO, address);
-       dmac_write (host->dma.io_port, TXADRMD, address >> 8);
-       dmac_write (host->dma.io_port, TXADRHI, 0);
-       dmac_write (host->dma.io_port, MODECON, mode);
-       dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+       dmac_write(host->dma.io_port, TXCNTLO, length);
+       dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+       dmac_write(host->dma.io_port, TXADRLO, address);
+       dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+       dmac_write(host->dma.io_port, TXADRHI, 0);
+       dmac_write(host->dma.io_port, MODECON, mode);
+       dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
 
 #if (DEBUG & DEBUG_DMA)
-       DBG(host->SCpnt, acornscsi_dumpdma (host, "strt"));
+       DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
 #endif
        host->dma.xfer_setup = 1;
     }
 }
 
 /*
- * Function: void acornscsi_dma_cleanup (AS_Host *host)
+ * Function: void acornscsi_dma_cleanup(AS_Host *host)
  * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
  * Params  : host - host to finish
  * Notes   : This is called when a command is:
@@ -1026,10 +1094,10 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
  *        : This must not return until all transfers are completed.
  */
 static
-void acornscsi_dma_cleanup (AS_Host *host)
+void acornscsi_dma_cleanup(AS_Host *host)
 {
-    dmac_write (host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr (host->dma.io_intr_clear);
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
 
     /*
      * Check for a pending transfer
@@ -1037,7 +1105,7 @@ void acornscsi_dma_cleanup (AS_Host *host)
     if (host->dma.xfer_required) {
        host->dma.xfer_required = 0;
        if (host->dma.direction == DMA_IN)
-           acornscsi_data_read (host, host->dma.xfer_ptr,
+           acornscsi_data_read(host, host->dma.xfer_ptr,
                                 host->dma.xfer_start, host->dma.xfer_length);
     }
 
@@ -1056,17 +1124,17 @@ void acornscsi_dma_cleanup (AS_Host *host)
        /*
         * Calculate number of bytes transferred from DMA.
         */
-       transferred = dmac_address (host->dma.io_port) - host->dma.start_addr;
+       transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
        host->dma.transferred += transferred;
 
        if (host->dma.direction == DMA_IN)
-           acornscsi_data_read (host, host->scsi.SCp.ptr,
+           acornscsi_data_read(host, host->scsi.SCp.ptr,
                                 host->dma.start_addr, transferred);
 
        /*
         * Update SCSI pointers
         */
-       acornscsi_data_updateptr (host, &host->scsi.SCp, transferred);
+       acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
 #if (DEBUG & DEBUG_DMA)
        DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
 #endif
@@ -1074,7 +1142,7 @@ void acornscsi_dma_cleanup (AS_Host *host)
 }
 
 /*
- * Function: void acornscsi_dmacintr (AS_Host *host)
+ * Function: void acornscsi_dmacintr(AS_Host *host)
  * Purpose : handle interrupts from DMAC device
  * Params  : host - host to process
  * Notes   : If reading, we schedule the read to main memory &
@@ -1084,21 +1152,21 @@ void acornscsi_dma_cleanup (AS_Host *host)
  *        : Called whenever DMAC finished it's current transfer.
  */
 static
-void acornscsi_dma_intr (AS_Host *host)
+void acornscsi_dma_intr(AS_Host *host)
 {
     unsigned int address, length, transferred;
 
 #if (DEBUG & DEBUG_DMA)
-    DBG(host->SCpnt, acornscsi_dumpdma (host, "inti"));
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
 #endif
 
-    dmac_write (host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr (host->dma.io_intr_clear);
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
 
     /*
      * Calculate amount transferred via DMA
      */
-    transferred = dmac_address (host->dma.io_port) - host->dma.start_addr;
+    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
     host->dma.transferred += transferred;
 
     /*
@@ -1111,12 +1179,12 @@ void acornscsi_dma_intr (AS_Host *host)
        host->dma.xfer_required = 1;
     }
 
-    acornscsi_data_updateptr (host, &host->scsi.SCp, transferred);
+    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
 
     /*
      * Allocate some buffer space, limited to half the on-board RAM size
      */
-    length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
     if (length) {
        host->dma.start_addr = address = host->dma.free_addr;
        host->dma.free_addr = (host->dma.free_addr + length) &
@@ -1126,19 +1194,19 @@ void acornscsi_dma_intr (AS_Host *host)
         * Transfer data to DMA memory
         */
        if (host->dma.direction == DMA_OUT)
-           acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr,
+           acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
                                length);
 
        length -= 1;
-       dmac_write (host->dma.io_port, TXCNTLO, length);
-       dmac_write (host->dma.io_port, TXCNTHI, length >> 8);
-       dmac_write (host->dma.io_port, TXADRLO, address);
-       dmac_write (host->dma.io_port, TXADRMD, address >> 8);
-       dmac_write (host->dma.io_port, TXADRHI, 0);
-       dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+       dmac_write(host->dma.io_port, TXCNTLO, length);
+       dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+       dmac_write(host->dma.io_port, TXADRLO, address);
+       dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+       dmac_write(host->dma.io_port, TXADRHI, 0);
+       dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
 
 #if (DEBUG & DEBUG_DMA)
-       DBG(host->SCpnt, acornscsi_dumpdma (host, "into"));
+       DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
 #endif
     } else {
        host->dma.xfer_setup = 0;
@@ -1149,48 +1217,48 @@ void acornscsi_dma_intr (AS_Host *host)
         * attention condition.  We continue giving one byte until
         * the device recognises the attention.
         */
-       if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) {
-           acornscsi_abortcmd (host, host->SCpnt->tag);
-
-           dmac_write (host->dma.io_port, TXCNTLO, 0);
-           dmac_write (host->dma.io_port, TXCNTHI, 0);
-           dmac_write (host->dma.io_port, TXADRLO, 0);
-           dmac_write (host->dma.io_port, TXADRMD, 0);
-           dmac_write (host->dma.io_port, TXADRHI, 0);
-           dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+       if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) {
+           acornscsi_abortcmd(host, host->SCpnt->tag);
+
+           dmac_write(host->dma.io_port, TXCNTLO, 0);
+           dmac_write(host->dma.io_port, TXCNTHI, 0);
+           dmac_write(host->dma.io_port, TXADRLO, 0);
+           dmac_write(host->dma.io_port, TXADRMD, 0);
+           dmac_write(host->dma.io_port, TXADRHI, 0);
+           dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
        }
 #endif
     }
 }
 
 /*
- * Function: void acornscsi_dma_xfer (AS_Host *host)
+ * Function: void acornscsi_dma_xfer(AS_Host *host)
  * Purpose : transfer data between AcornSCSI and memory
  * Params  : host - host to process
  */
 static
-void acornscsi_dma_xfer (AS_Host *host)
+void acornscsi_dma_xfer(AS_Host *host)
 {
     host->dma.xfer_required = 0;
 
     if (host->dma.direction == DMA_IN)
-       acornscsi_data_read (host, host->dma.xfer_ptr,
+       acornscsi_data_read(host, host->dma.xfer_ptr,
                                host->dma.xfer_start, host->dma.xfer_length);
 }
 
 /*
- * Function: void acornscsi_dma_adjust (AS_Host *host)
+ * Function: void acornscsi_dma_adjust(AS_Host *host)
  * Purpose : adjust DMA pointers & count for bytes transfered to
  *          SBIC but not SCSI bus.
  * Params  : host - host to adjust DMA count for
  */
 static
-void acornscsi_dma_adjust (AS_Host *host)
+void acornscsi_dma_adjust(AS_Host *host)
 {
     if (host->dma.xfer_setup) {
        signed long transferred;
 #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
-       DBG(host->SCpnt, acornscsi_dumpdma (host, "adji"));
+       DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
 #endif
        /*
         * Calculate correct DMA address - DMA is ahead of SCSI bus while
@@ -1205,17 +1273,17 @@ void acornscsi_dma_adjust (AS_Host *host)
         */
        transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
        if (transferred < 0)
-           printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
-                   host->host->host_no, acornscsi_target (host), transferred);
+           printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
+                   host->host->host_no, acornscsi_target(host), transferred);
        else if (transferred == 0)
            host->dma.xfer_setup = 0;
        else {
            transferred += host->dma.start_addr;
-           dmac_write (host->dma.io_port, TXADRLO, transferred);
-           dmac_write (host->dma.io_port, TXADRMD, transferred >> 8);
-           dmac_write (host->dma.io_port, TXADRHI, transferred >> 16);
+           dmac_write(host->dma.io_port, TXADRLO, transferred);
+           dmac_write(host->dma.io_port, TXADRMD, transferred >> 8);
+           dmac_write(host->dma.io_port, TXADRHI, transferred >> 16);
 #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
-           DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo"));
+           DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
 #endif
        }
     }
@@ -1225,66 +1293,88 @@ void acornscsi_dma_adjust (AS_Host *host)
 /* =========================================================================================
  * Data I/O
  */
+static int
+acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
+{
+       unsigned int asr, timeout = max_timeout;
+       int my_ptr = *ptr;
+
+       while (my_ptr < len) {
+               asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+               if (asr & ASR_DBR) {
+                       timeout = max_timeout;
+
+                       sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]);
+               } else if (asr & ASR_INT)
+                       break;
+               else if (--timeout == 0)
+                       break;
+               udelay(1);
+       }
+
+       *ptr = my_ptr;
+
+       return (timeout == 0) ? -1 : 0;
+}
+
 /*
- * Function: void acornscsi_sendcommand (AS_Host *host)
+ * Function: void acornscsi_sendcommand(AS_Host *host)
  * Purpose : send a command to a target
  * Params  : host - host which is connected to target
  */
-static
-void acornscsi_sendcommand (AS_Host *host)
+static void
+acornscsi_sendcommand(AS_Host *host)
 {
     Scsi_Cmnd *SCpnt = host->SCpnt;
-    unsigned int asr;
-    unsigned char *cmdptr, *cmdend;
-
-    sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0);
-    sbic_arm_writenext (host->scsi.io_port, 0);
-    sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
-    acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
-
-    cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command;
-    cmdend = SCpnt->cmnd + SCpnt->cmd_len;
-
-    while (cmdptr < cmdend) {
-       asr = sbic_arm_read (host->scsi.io_port, ASR);
-       if (asr & ASR_DBR)
-           sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++);
-       else if (asr & ASR_INT)
-           break;
-    }
-    if (cmdptr >= cmdend)
-       host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd;
+
+    sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+    sbic_arm_writenext(host->scsi.io_port, 0);
+    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
+
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+    if (acornscsi_write_pio(host, SCpnt->cmnd,
+       (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
+       printk("scsi%d: timeout while sending command\n", host->host->host_no);
+
     host->scsi.phase = PHASE_COMMAND;
 }
 
 static
-void acornscsi_sendmessage (AS_Host *host)
+void acornscsi_sendmessage(AS_Host *host)
 {
-    unsigned int message_length = msgqueue_msglength (&host->scsi.msgs);
-    int msgnr;
+    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
+    unsigned int msgnr;
     struct message *msg;
 
 #if (DEBUG & DEBUG_MESSAGES)
-    printk ("scsi%d.%c: sending message ",
-           host->host->host_no, acornscsi_target (host));
+    printk("scsi%d.%c: sending message ",
+           host->host->host_no, acornscsi_target(host));
 #endif
 
     switch (message_length) {
     case 0:
-       acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
-       while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
-       sbic_arm_write (host->scsi.io_port, DATA, NOP);
+       acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+       acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
+
+       sbic_arm_write(host->scsi.io_port, DATA, NOP);
+
        host->scsi.last_message = NOP;
 #if (DEBUG & DEBUG_MESSAGES)
-       printk ("NOP");
+       printk("NOP");
 #endif
        break;
 
     case 1:
-       acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
+       acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
        msg = msgqueue_getmsg(&host->scsi.msgs, 0);
-       while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
-       sbic_arm_write (host->scsi.io_port, DATA, msg->msg[0]);
+
+       acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
+
+       sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]);
+
        host->scsi.last_message = msg->msg[0];
 #if (DEBUG & DEBUG_MESSAGES)
        print_msg(msg->msg);
@@ -1300,86 +1390,85 @@ void acornscsi_sendmessage (AS_Host *host)
         *  initiator.  This provides an interlock so that the
         *  initiator can determine which message byte is rejected.
         */
-       sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0);
-       sbic_arm_writenext (host->scsi.io_port, 0);
-       sbic_arm_writenext (host->scsi.io_port, message_length);
-       acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
+       sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+       sbic_arm_writenext(host->scsi.io_port, 0);
+       sbic_arm_writenext(host->scsi.io_port, message_length);
+       acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
 
        msgnr = 0;
        while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
-           unsigned int asr, i;
+           unsigned int i;
 #if (DEBUG & DEBUG_MESSAGES)
-           print_msg (msg);
+           print_msg(msg);
 #endif
-           for (i = 0; i < msg->length;) {
-               asr = sbic_arm_read (host->scsi.io_port, ASR);
-               if (asr & ASR_DBR)
-                   sbic_arm_write (host->scsi.io_port, DATA, msg->msg[i++]);
-               if (asr & ASR_INT)
-                   break;
-           }
+           i = 0;
+           if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
+               printk("scsi%d: timeout while sending message\n", host->host->host_no);
+
            host->scsi.last_message = msg->msg[0];
            if (msg->msg[0] == EXTENDED_MESSAGE)
                host->scsi.last_message |= msg->msg[2] << 8;
-           if (asr & ASR_INT)
+
+           if (i != msg->length)
                break;
        }
        break;
     }
 #if (DEBUG & DEBUG_MESSAGES)
-    printk ("\n");
+    printk("\n");
 #endif
 }
 
 /*
- * Function: void acornscsi_readstatusbyte (AS_Host *host)
+ * Function: void acornscsi_readstatusbyte(AS_Host *host)
  * Purpose : Read status byte from connected target
  * Params  : host - host connected to target
  */
 static
-void acornscsi_readstatusbyte (AS_Host *host)
+void acornscsi_readstatusbyte(AS_Host *host)
 {
-    acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT);
-    while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
-
-    host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA);
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
+    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA);
 }
 
 /*
- * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host)
+ * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
  * Purpose : Read one message byte from connected target
  * Params  : host - host connected to target
  */
 static
-unsigned char acornscsi_readmessagebyte (AS_Host *host)
+unsigned char acornscsi_readmessagebyte(AS_Host *host)
 {
     unsigned char message;
 
-    acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
-    while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
 
-    message = sbic_arm_read (host->scsi.io_port, DATA);
+    message = sbic_arm_read(host->scsi.io_port, DATA);
 
     /* wait for MSGIN-XFER-PAUSED */
-    while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0);
-    sbic_arm_read (host->scsi.io_port, SSR);
+    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
+
+    sbic_arm_read(host->scsi.io_port, SSR);
 
     return message;
 }
 
 /*
- * Function: void acornscsi_message (AS_Host *host)
+ * Function: void acornscsi_message(AS_Host *host)
  * Purpose : Read complete message from connected target & action message
  * Params  : host - host connected to target
  */
 static
-void acornscsi_message (AS_Host *host)
+void acornscsi_message(AS_Host *host)
 {
     unsigned char message[16];
     unsigned int msgidx = 0, msglen = 1;
 
     do {
-       message[msgidx] = acornscsi_readmessagebyte (host);
+       message[msgidx] = acornscsi_readmessagebyte(host);
 
        switch (msgidx) {
        case 0:
@@ -1395,17 +1484,17 @@ void acornscsi_message (AS_Host *host)
        }
        msgidx += 1;
        if (msgidx < msglen) {
-           acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+           acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
 
            /* wait for next msg-in */
-           while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0);
-           sbic_arm_read (host->scsi.io_port, SSR);
+           acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
+           sbic_arm_read(host->scsi.io_port, SSR);
        }
     } while (msgidx < msglen);
 
 #if (DEBUG & DEBUG_MESSAGES)
     printk("scsi%d.%c: message in: ",
-           host->host->host_no, acornscsi_target (host));
+           host->host->host_no, acornscsi_target(host));
     print_msg(message);
     printk("\n");
 #endif
@@ -1419,7 +1508,7 @@ void acornscsi_message (AS_Host *host)
         */
        if (message[0] == SIMPLE_QUEUE_TAG)
            host->scsi.reconnected.tag = message[1];
-       if (acornscsi_reconnect_finish (host))
+       if (acornscsi_reconnect_finish(host))
            host->scsi.phase = PHASE_MSGIN;
     }
 
@@ -1429,7 +1518,7 @@ void acornscsi_message (AS_Host *host)
     case COMMAND_COMPLETE:
        if (host->scsi.phase != PHASE_STATUSIN) {
            printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
-                   host->host->host_no, acornscsi_target (host));
+                   host->host->host_no, acornscsi_target(host));
            acornscsi_dumplog(host, host->SCpnt->target);
        }
        host->scsi.phase = PHASE_DONE;
@@ -1443,7 +1532,7 @@ void acornscsi_message (AS_Host *host)
         *  direct the initiator to copy the active data pointer to
         *  the saved data pointer for the current I/O process.
         */
-       acornscsi_dma_cleanup (host);
+       acornscsi_dma_cleanup(host);
        host->SCpnt->SCp = host->scsi.SCp;
        host->SCpnt->SCp.sent_command = 0;
        host->scsi.phase = PHASE_MSGIN;
@@ -1459,7 +1548,7 @@ void acornscsi_message (AS_Host *host)
         *  status pointers shall be restored to the beginning of
         *  the present command and status areas.'
         */
-       acornscsi_dma_cleanup (host);
+       acornscsi_dma_cleanup(host);
        host->scsi.SCp = host->SCpnt->SCp;
        host->scsi.phase = PHASE_MSGIN;
        break;
@@ -1474,7 +1563,7 @@ void acornscsi_message (AS_Host *host)
         *  message.  When reconnection is completed, the most recent
         *  saved pointer values are restored.'
         */
-       acornscsi_dma_cleanup (host);
+       acornscsi_dma_cleanup(host);
        host->scsi.phase = PHASE_DISCONNECT;
        break;
 
@@ -1493,8 +1582,8 @@ void acornscsi_message (AS_Host *host)
        /*
         * If we have any messages waiting to go out, then assert ATN now
         */
-       if (msgqueue_msglength (&host->scsi.msgs))
-           acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
+       if (msgqueue_msglength(&host->scsi.msgs))
+           acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
 
        switch (host->scsi.last_message) {
 #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
@@ -1507,21 +1596,21 @@ void acornscsi_message (AS_Host *host)
             *  message is received, it shall respond with a MESSAGE REJECT
             *  message and accept the I/O process as if it were untagged.
             */
-           printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
-                   host->host->host_no, acornscsi_target (host));
+           printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
+                   host->host->host_no, acornscsi_target(host));
            host->SCpnt->device->tagged_queue = 0;
-           set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
+           set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
            break;
 #endif
        case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
            /*
             * Target can't handle synchronous transfers
             */
-           printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
-                   host->host->host_no, acornscsi_target (host));
+           printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
+                   host->host->host_no, acornscsi_target(host));
            host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA;
            host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS;
-           sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+           sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
            break;
 
        default:
@@ -1535,8 +1624,8 @@ void acornscsi_message (AS_Host *host)
 
     case SIMPLE_QUEUE_TAG:
        /* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */
-       printk ("scsi%d.%c: reconnect queue tag %02X\n",
-               host->host->host_no, acornscsi_target (host),
+       printk("scsi%d.%c: reconnect queue tag %02X\n",
+               host->host->host_no, acornscsi_target(host),
                message[1]);
        break;
 
@@ -1552,26 +1641,26 @@ void acornscsi_message (AS_Host *host)
                 * and the target retries fail, then we fallback to asynchronous mode
                 */
                host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED;
-               printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
+               printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
                        host->host->host_no, acornscsi_target(host),
                        message[4], message[3] * 4);
                host->device[host->SCpnt->target].sync_xfer =
-                       calc_sync_xfer (message[3] * 4, message[4]);
+                       calc_sync_xfer(message[3] * 4, message[4]);
            } else {
                unsigned char period, length;
                /*
                 * Target requested synchronous transfers.  The agreement is only
                 * to be in operation AFTER the target leaves message out phase.
                 */
-               acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
-               period = max (message[3], sdtr_period / 4);
-               length = min (message[4], sdtr_size);
-               msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
+               acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+               period = max(message[3], sdtr_period / 4);
+               length = min(message[4], sdtr_size);
+               msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
                                 EXTENDED_SDTR, period, length);
                host->device[host->SCpnt->target].sync_xfer =
-                       calc_sync_xfer (period * 4, length);
+                       calc_sync_xfer(period * 4, length);
            }
-           sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+           sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
            break;
 #else
            /* We do not accept synchronous transfers.  Respond with a
@@ -1584,9 +1673,9 @@ void acornscsi_message (AS_Host *host)
             * to a wide data transfer request.
             */
        default:
-           acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
-           msgqueue_flush (&host->scsi.msgs);
-           msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT);
+           acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+           msgqueue_flush(&host->scsi.msgs);
+           msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
            break;
        }
        break;
@@ -1607,19 +1696,19 @@ void acornscsi_message (AS_Host *host)
             * if there are more linked commands available.
             */
            if (!host->SCpnt->next_link) {
-               printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
-                       instance->host_no, acornscsi_target (host), host->SCpnt->tag);
-               acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
-               msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
+               printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
+                       instance->host_no, acornscsi_target(host), host->SCpnt->tag);
+               acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+               msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
            } else {
                Scsi_Cmnd *SCpnt = host->SCpnt;
 
-               acornscsi_dma_cleanup (host);
+               acornscsi_dma_cleanup(host);
 
                host->SCpnt = host->SCpnt->next_link;
                host->SCpnt->tag = SCpnt->tag;
                SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
-               SCpnt->done (SCpnt);
+               SCpnt->done(SCpnt);
 
                /* initialise host->SCpnt->SCp */
            }
@@ -1628,42 +1717,42 @@ void acornscsi_message (AS_Host *host)
 #endif
 
     default: /* reject message */
-       printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
-               host->host->host_no, acornscsi_target (host),
+       printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
+               host->host->host_no, acornscsi_target(host),
                message[0]);
-       acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
-       msgqueue_flush (&host->scsi.msgs);
-       msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT);
+       acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+       msgqueue_flush(&host->scsi.msgs);
+       msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
        host->scsi.phase = PHASE_MSGIN;
        break;
     }
-    acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
 }
 
 /*
- * Function: int acornscsi_buildmessages (AS_Host *host)
+ * Function: int acornscsi_buildmessages(AS_Host *host)
  * Purpose : build the connection messages for a host
  * Params  : host - host to add messages to
  */
 static
-void acornscsi_buildmessages (AS_Host *host)
+void acornscsi_buildmessages(AS_Host *host)
 {
 #if 0
     /* does the device need resetting? */
     if (cmd_reset) {
-       msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET);
+       msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
        return;
     }
 #endif
 
-    msgqueue_addmsg (&host->scsi.msgs, 1,
+    msgqueue_addmsg(&host->scsi.msgs, 1,
                     IDENTIFY(host->device[host->SCpnt->target].disconnect_ok,
                             host->SCpnt->lun));
 
 #if 0
     /* does the device need the current command aborted */
     if (cmd_aborted) {
-       acornscsi_abortcmd (host->SCpnt->tag);
+       acornscsi_abortcmd(host->SCpnt->tag);
        return;
     }
 #endif
@@ -1678,14 +1767,14 @@ void acornscsi_buildmessages (AS_Host *host)
            tag_type = HEAD_OF_QUEUE_TAG;
        else
            tag_type = SIMPLE_QUEUE_TAG;
-       msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
+       msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
     }
 #endif
 
 #ifdef CONFIG_SCSI_ACORNSCSI_SYNC
     if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) {
        host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST;
-       msgqueue_addmsg (&host->scsi.msgs, 5,
+       msgqueue_addmsg(&host->scsi.msgs, 5,
                         EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
                         sdtr_period / 4, sdtr_size);
     }
@@ -1693,29 +1782,29 @@ void acornscsi_buildmessages (AS_Host *host)
 }
 
 /*
- * Function: int acornscsi_starttransfer (AS_Host *host)
+ * Function: int acornscsi_starttransfer(AS_Host *host)
  * Purpose : transfer data to/from connected target
  * Params  : host - host to which target is connected
  * Returns : 0 if failure
  */
 static
-int acornscsi_starttransfer (AS_Host *host)
+int acornscsi_starttransfer(AS_Host *host)
 {
     int residual;
 
     if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
-       printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
-               host->host->host_no, acornscsi_target (host));
+       printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
+               host->host->host_no, acornscsi_target(host));
        return 0;
     }
 
     residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
 
-    sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
-    sbic_arm_writenext (host->scsi.io_port, residual >> 16);
-    sbic_arm_writenext (host->scsi.io_port, residual >> 8);
-    sbic_arm_writenext (host->scsi.io_port, residual);
-    acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
+    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 16);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 8);
+    sbic_arm_writenext(host->scsi.io_port, residual);
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
     return 1;
 }
 
@@ -1723,7 +1812,7 @@ int acornscsi_starttransfer (AS_Host *host)
  * Connection & Disconnection
  */
 /*
- * Function : acornscsi_reconnect (AS_Host *host)
+ * Function : acornscsi_reconnect(AS_Host *host)
  * Purpose  : reconnect a previously disconnected command
  * Params   : host - host specific data
  * Remarks  : SCSI spec says:
@@ -1731,27 +1820,27 @@ int acornscsi_starttransfer (AS_Host *host)
  *              of saved pointers upon reconnection of the I/O process'
  */
 static
-int acornscsi_reconnect (AS_Host *host)
+int acornscsi_reconnect(AS_Host *host)
 {
     unsigned int target, lun, ok = 0;
 
-    target = sbic_arm_read (host->scsi.io_port, SOURCEID);
+    target = sbic_arm_read(host->scsi.io_port, SOURCEID);
 
     if (!(target & 8))
-       printk (KERN_ERR "scsi%d: invalid source id after reselection "
+       printk(KERN_ERR "scsi%d: invalid source id after reselection "
                "- device fault?\n",
                host->host->host_no);
 
     target &= 7;
 
     if (host->SCpnt && !host->scsi.disconnectable) {
-       printk (KERN_ERR "scsi%d.%d: reconnected while command in "
+       printk(KERN_ERR "scsi%d.%d: reconnected while command in "
                "progress to target %d?\n",
                host->host->host_no, target, host->SCpnt->target);
        host->SCpnt = NULL;
     }
 
-    lun = sbic_arm_read (host->scsi.io_port, DATA) & 7;
+    lun = sbic_arm_read(host->scsi.io_port, DATA) & 7;
 
     host->scsi.reconnected.target = target;
     host->scsi.reconnected.lun = lun;
@@ -1761,7 +1850,7 @@ int acornscsi_reconnect (AS_Host *host)
        host->SCpnt->target == target && host->SCpnt->lun == lun)
        ok = 1;
 
-    if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun))
+    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
        ok = 1;
 
     ADD_STATUS(target, 0x81, host->scsi.phase, 0);
@@ -1770,26 +1859,28 @@ int acornscsi_reconnect (AS_Host *host)
        host->scsi.phase = PHASE_RECONNECTED;
     } else {
        /* this doesn't seem to work */
-       printk (KERN_ERR "scsi%d.%c: reselected with no command "
+       printk(KERN_ERR "scsi%d.%c: reselected with no command "
                "to reconnect with\n",
                host->host->host_no, '0' + target);
-       acornscsi_dumplog (host, target);
-       acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
-       msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
-       host->scsi.phase = PHASE_ABORTED;
+       acornscsi_dumplog(host, target);
+       acornscsi_abortcmd(host, 0);
+       if (host->SCpnt) {
+           queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+           host->SCpnt = NULL;
+       }
     }
-    acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
     return !ok;
 }
 
 /*
- * Function: int acornscsi_reconect_finish (AS_Host *host)
+ * Function: int acornscsi_reconect_finish(AS_Host *host)
  * Purpose : finish reconnecting a command
  * Params  : host - host to complete
  * Returns : 0 if failed
  */
 static
-int acornscsi_reconnect_finish (AS_Host *host)
+int acornscsi_reconnect_finish(AS_Host *host)
 {
     if (host->scsi.disconnectable && host->SCpnt) {
        host->scsi.disconnectable = 0;
@@ -1797,45 +1888,44 @@ int acornscsi_reconnect_finish (AS_Host *host)
            host->SCpnt->lun    == host->scsi.reconnected.lun &&
            host->SCpnt->tag    == host->scsi.reconnected.tag) {
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-           DBG(host->SCpnt, printk ("scsi%d.%c: reconnected",
-                   host->host->host_no, acornscsi_target (host)));
+           DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
+                   host->host->host_no, acornscsi_target(host)));
 #endif
        } else {
-           queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt);
+           queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-           DBG(host->SCpnt, printk ("scsi%d.%c: had to move command "
+           DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
                    "to disconnected queue\n",
-                   host->host->host_no, acornscsi_target (host)));
+                   host->host->host_no, acornscsi_target(host)));
 #endif
            host->SCpnt = NULL;
        }
     }
     if (!host->SCpnt) {
-       host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected,
+       host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
                                host->scsi.reconnected.target,
                                host->scsi.reconnected.lun,
                                host->scsi.reconnected.tag);
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-       DBG(host->SCpnt, printk ("scsi%d.%c: had to get command",
-               host->host->host_no, acornscsi_target (host)));
+       DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
+               host->host->host_no, acornscsi_target(host)));
 #endif
     }
 
-    if (!host->SCpnt) {
-       acornscsi_abortcmd (host, host->scsi.reconnected.tag);
-       host->scsi.phase = PHASE_ABORTED;
-    } else {
+    if (!host->SCpnt)
+       acornscsi_abortcmd(host, host->scsi.reconnected.tag);
+    else {
        /*
         * Restore data pointer from SAVED pointers.
         */
        host->scsi.SCp = host->SCpnt->SCp;
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-       printk (", data pointers: [%p, %X]",
+       printk(", data pointers: [%p, %X]",
                host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
 #endif
     }
 #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-    printk ("\n");
+    printk("\n");
 #endif
 
     host->dma.transferred = host->scsi.SCp.scsi_xferred;
@@ -1844,47 +1934,48 @@ int acornscsi_reconnect_finish (AS_Host *host)
 }
 
 /*
- * Function: void acornscsi_disconnect_unexpected (AS_Host *host)
+ * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
  * Purpose : handle an unexpected disconnect
  * Params  : host - host on which disconnect occurred
  */
 static
-void acornscsi_disconnect_unexpected (AS_Host *host)
+void acornscsi_disconnect_unexpected(AS_Host *host)
 {
-    printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n",
-           host->host->host_no, acornscsi_target (host));
+    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
+           host->host->host_no, acornscsi_target(host));
 #if (DEBUG & DEBUG_ABORT)
-    acornscsi_dumplog (host, 8);
+    acornscsi_dumplog(host, 8);
 #endif
 
-    acornscsi_done (host, &host->SCpnt, DID_ABORT);
+    acornscsi_done(host, &host->SCpnt, DID_ERROR);
 }
 
 /*
- * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag)
+ * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
  * Purpose : abort a currently executing command
  * Params  : host - host with connected command to abort
  *          tag  - tag to abort
  */
 static
-void acornscsi_abortcmd (AS_Host *host, unsigned char tag)
+void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
 {
-    sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN);
+    host->scsi.phase = PHASE_ABORTED;
+    sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN);
 
-    msgqueue_flush (&host->scsi.msgs);
+    msgqueue_flush(&host->scsi.msgs);
 #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
     if (tag)
-       msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag);
+       msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
     else
 #endif
-       msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
+       msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
 }
 
 /* ==========================================================================================
  * Interrupt routines.
  */
 /*
- * Function: int acornscsi_sbicintr (AS_Host *host)
+ * Function: int acornscsi_sbicintr(AS_Host *host)
  * Purpose : handle interrupts from SCSI device
  * Params  : host - host to process
  * Returns : INTR_PROCESS if expecting another SBIC interrupt
@@ -1892,15 +1983,15 @@ void acornscsi_abortcmd (AS_Host *host, unsigned char tag)
  *          INTR_NEXT_COMMAND if we have finished processing the command
  */
 static
-intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
+intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
 {
     unsigned int asr, ssr;
 
-    asr = sbic_arm_read (host->scsi.io_port, ASR);
+    asr = sbic_arm_read(host->scsi.io_port, ASR);
     if (!(asr & ASR_INT))
        return INTR_IDLE;
 
-    ssr = sbic_arm_read (host->scsi.io_port, SSR);
+    ssr = sbic_arm_read(host->scsi.io_port, SSR);
 
 #if (DEBUG & DEBUG_PHASES)
     print_sbic_status(asr, ssr, host->scsi.phase);
@@ -1913,23 +2004,23 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
 
     switch (ssr) {
     case 0x00:                         /* reset state - not advanced                   */
-       printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
+       printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
                host->host->host_no);
        /* setup sbic - WD33C93A */
-       sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
-       sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET);
+       sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+       sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
        return INTR_IDLE;
 
     case 0x01:                         /* reset state - advanced                       */
-       sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
-       sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
-       sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
-       sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
-       msgqueue_flush (&host->scsi.msgs);
+       sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+       sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+       sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+       sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+       msgqueue_flush(&host->scsi.msgs);
        return INTR_IDLE;
 
     case 0x41:                         /* unexpected disconnect aborted command        */
-       acornscsi_disconnect_unexpected (host);
+       acornscsi_disconnect_unexpected(host);
        return INTR_NEXT_COMMAND;
     }
 
@@ -1939,35 +2030,35 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
        case 0x11:                      /* -> PHASE_CONNECTED                           */
            /* BUS FREE -> SELECTION */
            host->scsi.phase = PHASE_CONNECTED;
-           msgqueue_flush (&host->scsi.msgs);
+           msgqueue_flush(&host->scsi.msgs);
            host->dma.transferred = host->scsi.SCp.scsi_xferred;
            /* 33C93 gives next interrupt indicating bus phase */
-           asr = sbic_arm_read (host->scsi.io_port, ASR);
+           asr = sbic_arm_read(host->scsi.io_port, ASR);
            if (!(asr & ASR_INT))
                break;
-           ssr = sbic_arm_read (host->scsi.io_port, SSR);
+           ssr = sbic_arm_read(host->scsi.io_port, SSR);
            ADD_STATUS(8, ssr, host->scsi.phase, 1);
            ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1);
            goto connected;
            
        case 0x42:                      /* select timed out                             */
                                        /* -> PHASE_IDLE                                */
-           acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT);
+           acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
            return INTR_NEXT_COMMAND;
 
        case 0x81:                      /* -> PHASE_RECONNECTED or PHASE_ABORTED        */
            /* BUS FREE -> RESELECTION */
            host->origSCpnt = host->SCpnt;
            host->SCpnt = NULL;
-           msgqueue_flush (&host->scsi.msgs);
-           acornscsi_reconnect (host);
+           msgqueue_flush(&host->scsi.msgs);
+           acornscsi_reconnect(host);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
-           acornscsi_abortcmd (host, host->SCpnt->tag);
+           printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+           acornscsi_abortcmd(host, host->SCpnt->tag);
        }
        return INTR_PROCESSING;
 
@@ -1977,12 +2068,12 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
 #ifdef NONSTANDARD
        case 0x8a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
            /* SELECTION -> COMMAND */
-           acornscsi_sendcommand (host);
+           acornscsi_sendcommand(host);
            break;
 
        case 0x8b:                      /* -> PHASE_STATUS                              */
            /* SELECTION -> STATUS */
-           acornscsi_readstatusbyte (host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 #endif
@@ -1990,55 +2081,57 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* SELECTION ->MESSAGE OUT */
            host->scsi.phase = PHASE_MSGOUT;
-           acornscsi_buildmessages (host);
-           acornscsi_sendmessage (host);
+           acornscsi_buildmessages(host);
+           acornscsi_sendmessage(host);
            break;
 
        /* these should not happen */
        case 0x85:                      /* target disconnected                          */
-           acornscsi_done (host, &host->SCpnt, DID_ERROR);
+           acornscsi_done(host, &host->SCpnt, DID_ERROR);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
-           acornscsi_abortcmd (host, host->SCpnt->tag);
+           printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+           acornscsi_abortcmd(host, host->SCpnt->tag);
        }
        return INTR_PROCESSING;
 
     case PHASE_MSGOUT:                 /* STATE: connected & sent IDENTIFY message     */
        /*
-        * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase
+        * SCSI standard says that MESSAGE OUT phases can be followed by a
+        * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
         */
        switch (ssr) {
-       case 0x8a:
+       case 0x8a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
        case 0x1a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
            /* MESSAGE OUT -> COMMAND */
-           acornscsi_sendcommand (host);
+           acornscsi_sendcommand(host);
            break;
 
+       case 0x8b:                      /* -> PHASE_STATUS                              */
        case 0x1b:                      /* -> PHASE_STATUS                              */
            /* MESSAGE OUT -> STATUS */
-           acornscsi_readstatusbyte (host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
-        case 0x4f:
+       case 0x4f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
            /* MESSAGE OUT -> MESSAGE IN */
-           acornscsi_message (host);
+           acornscsi_message(host);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2047,43 +2140,43 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
        case 0x18:                      /* -> PHASE_DATAOUT                             */
            /* COMMAND -> DATA OUT */
            if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
-               acornscsi_abortcmd (host, host->SCpnt->tag);
-           acornscsi_dma_setup (host, DMA_OUT);
-           if (!acornscsi_starttransfer (host))
-               acornscsi_abortcmd (host, host->SCpnt->tag);
+               acornscsi_abortcmd(host, host->SCpnt->tag);
+           acornscsi_dma_setup(host, DMA_OUT);
+           if (!acornscsi_starttransfer(host))
+               acornscsi_abortcmd(host, host->SCpnt->tag);
            host->scsi.phase = PHASE_DATAOUT;
            return INTR_IDLE;
 
        case 0x19:                      /* -> PHASE_DATAIN                              */
            /* COMMAND -> DATA IN */
            if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
-               acornscsi_abortcmd (host, host->SCpnt->tag);
-           acornscsi_dma_setup (host, DMA_IN);
-           if (!acornscsi_starttransfer (host))
-               acornscsi_abortcmd (host, host->SCpnt->tag);
+               acornscsi_abortcmd(host, host->SCpnt->tag);
+           acornscsi_dma_setup(host, DMA_IN);
+           if (!acornscsi_starttransfer(host))
+               acornscsi_abortcmd(host, host->SCpnt->tag);
            host->scsi.phase = PHASE_DATAIN;
            return INTR_IDLE;
 
        case 0x1b:                      /* -> PHASE_STATUS                              */
            /* COMMAND -> STATUS */
-           acornscsi_readstatusbyte (host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
            /* COMMAND -> MESSAGE OUT */
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
            /* COMMAND -> MESSAGE IN */
-           acornscsi_message (host);
+           acornscsi_message(host);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2094,19 +2187,19 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
            host->scsi.phase = PHASE_IDLE;
            host->stats.disconnects += 1;
        } else {
-           printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_NEXT_COMMAND;
 
     case PHASE_IDLE:                   /* STATE: disconnected                          */
        if (ssr == 0x81)                /* -> PHASE_RECONNECTED or PHASE_ABORTED        */
-           acornscsi_reconnect (host);
+           acornscsi_reconnect(host);
        else {
-           printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2119,54 +2212,54 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
         * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
         * reconnect I_T_L command
         */
-       if (ssr != 0x8f && !acornscsi_reconnect_finish (host))
+       if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
            return INTR_IDLE;
        ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq);
        switch (ssr) {
        case 0x88:                      /* data out phase                               */
                                        /* -> PHASE_DATAOUT                             */
            /* MESSAGE IN -> DATA OUT */
-           acornscsi_dma_setup (host, DMA_OUT);
-           if (!acornscsi_starttransfer (host))
-               acornscsi_abortcmd (host, host->SCpnt->tag);
+           acornscsi_dma_setup(host, DMA_OUT);
+           if (!acornscsi_starttransfer(host))
+               acornscsi_abortcmd(host, host->SCpnt->tag);
            host->scsi.phase = PHASE_DATAOUT;
            return INTR_IDLE;
 
        case 0x89:                      /* data in phase                                */
                                        /* -> PHASE_DATAIN                              */
            /* MESSAGE IN -> DATA IN */
-           acornscsi_dma_setup (host, DMA_IN);
-           if (!acornscsi_starttransfer (host))
-               acornscsi_abortcmd (host, host->SCpnt->tag);
+           acornscsi_dma_setup(host, DMA_IN);
+           if (!acornscsi_starttransfer(host))
+               acornscsi_abortcmd(host, host->SCpnt->tag);
            host->scsi.phase = PHASE_DATAIN;
            return INTR_IDLE;
 
        case 0x8a:                      /* command out                                  */
            /* MESSAGE IN -> COMMAND */
-           acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED       */
+           acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
            break;
 
        case 0x8b:                      /* status in                                    */
                                        /* -> PHASE_STATUSIN                            */
            /* MESSAGE IN -> STATUS */
-           acornscsi_readstatusbyte (host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 
        case 0x8e:                      /* message out                                  */
                                        /* -> PHASE_MSGOUT                              */
            /* MESSAGE IN -> MESSAGE OUT */
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
        case 0x8f:                      /* message in                                   */
-           acornscsi_message (host);   /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
+           acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2177,41 +2270,45 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
         */
        switch (ssr) {
        case 0x19:                      /* -> PHASE_DATAIN                              */
-           acornscsi_abortcmd (host, host->SCpnt->tag);
+       case 0x89:                      /* -> PHASE_DATAIN                              */
+           acornscsi_abortcmd(host, host->SCpnt->tag);
            return INTR_IDLE;
 
-       case 0x4b:                      /* -> PHASE_STATUSIN                            */
        case 0x1b:                      /* -> PHASE_STATUSIN                            */
+       case 0x4b:                      /* -> PHASE_STATUSIN                            */
+       case 0x8b:                      /* -> PHASE_STATUSIN                            */
            /* DATA IN -> STATUS */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_readstatusbyte (host);
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
+       case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* DATA IN -> MESSAGE OUT */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_sendmessage (host);
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_sendmessage(host);
            break;
 
        case 0x1f:                      /* message in                                   */
        case 0x4f:                      /* message in                                   */
+       case 0x8f:                      /* message in                                   */
            /* DATA IN -> MESSAGE IN */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_message (host);   /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2222,58 +2319,69 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
         */
        switch (ssr) {
        case 0x18:                      /* -> PHASE_DATAOUT                             */
-           acornscsi_abortcmd (host, host->SCpnt->tag);
+       case 0x88:                      /* -> PHASE_DATAOUT                             */
+           acornscsi_abortcmd(host, host->SCpnt->tag);
            return INTR_IDLE;
 
-       case 0x4b:                      /* -> PHASE_STATUSIN                            */
        case 0x1b:                      /* -> PHASE_STATUSIN                            */
+       case 0x4b:                      /* -> PHASE_STATUSIN                            */
+       case 0x8b:                      /* -> PHASE_STATUSIN                            */
            /* DATA OUT -> STATUS */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_dma_adjust (host);
-           acornscsi_readstatusbyte (host);
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_dma_adjust(host);
+           acornscsi_readstatusbyte(host);
            host->scsi.phase = PHASE_STATUSIN;
            break;
 
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
+       case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* DATA OUT -> MESSAGE OUT */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_dma_adjust (host);
-           acornscsi_sendmessage (host);
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_dma_adjust(host);
+           acornscsi_sendmessage(host);
            break;
 
        case 0x1f:                      /* message in                                   */
        case 0x4f:                      /* message in                                   */
+       case 0x8f:                      /* message in                                   */
            /* DATA OUT -> MESSAGE IN */
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-                                         acornscsi_sbic_xfcount (host);
-           acornscsi_dma_stop (host);
-           acornscsi_dma_adjust (host);
-           acornscsi_message (host);   /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
+                                         acornscsi_sbic_xfcount(host);
+           acornscsi_dma_stop(host);
+           acornscsi_dma_adjust(host);
+           acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
     case PHASE_STATUSIN:               /* STATE: status in complete                    */
-       if (ssr == 0x1f)                /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+       switch (ssr) {
+       case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+       case 0x8f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
            /* STATUS -> MESSAGE IN */
-           acornscsi_message (host);
-       else if (ssr == 0x1e)           /* -> PHASE_MSGOUT                              */
+           acornscsi_message(host);
+           break;
+
+       case 0x1e:                      /* -> PHASE_MSGOUT                              */
+       case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* STATUS -> MESSAGE OUT */
-           acornscsi_sendmessage (host);
-       else {
-           printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           acornscsi_sendmessage(host);
+           break;
+
+       default:
+           printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
@@ -2281,78 +2389,93 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
        switch (ssr) {
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
+       case 0x8e:                      /* -> PHASE_MSGOUT                              */
            /* MESSAGE IN -> MESSAGE OUT */
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
        case 0x2f:
        case 0x4f:
        case 0x8f:
-           acornscsi_message (host);
+           acornscsi_message(host);
+           break;
+
+       case 0x85:
+           printk("scsi%d.%c: strange message in disconnection\n",
+               host->host->host_no, acornscsi_target(host));
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+           acornscsi_done(host, &host->SCpnt, DID_ERROR);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
     case PHASE_DONE:                   /* STATE: received status & message             */
        switch (ssr) {
        case 0x85:                      /* -> PHASE_IDLE                                */
-           acornscsi_done (host, &host->SCpnt, DID_OK);
+           acornscsi_done(host, &host->SCpnt, DID_OK);
            return INTR_NEXT_COMMAND;
 
+       case 0x1e:
        case 0x8e:
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
     case PHASE_ABORTED:
        switch (ssr) {
        case 0x85:
-           acornscsi_done (host, &host->SCpnt, DID_ABORT);
+           if (host->SCpnt)
+               acornscsi_done(host, &host->SCpnt, DID_ABORT);
+           else {
+               clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
+                         host->busyluns);
+               host->scsi.phase = PHASE_IDLE;
+           }
            return INTR_NEXT_COMMAND;
 
        case 0x1e:
        case 0x2e:
        case 0x4e:
        case 0x8e:
-           acornscsi_sendmessage (host);
+           acornscsi_sendmessage(host);
            break;
 
        default:
-           printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
-                   host->host->host_no, acornscsi_target (host), ssr);
-           acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+           printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
+                   host->host->host_no, acornscsi_target(host), ssr);
+           acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
        }
        return INTR_PROCESSING;
 
     default:
-       printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
-               host->host->host_no, acornscsi_target (host), ssr);
-       acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+       printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
+               host->host->host_no, acornscsi_target(host), ssr);
+       acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
     }
     return INTR_PROCESSING;
 }
 
 /*
- * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
+ * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
  * Purpose  : handle interrupts from Acorn SCSI card
  * Params   : irq    - interrupt number
  *           dev_id - device specific data (AS_Host structure)
  *           regs   - processor registers when interrupt occurred
  */
 static
-void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
+void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
     AS_Host *host = (AS_Host *)dev_id;
     intr_ret_t ret;
@@ -2360,21 +2483,21 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
     int in_irq = 0;
 
     if (host->scsi.interrupt)
-       printk ("scsi%d: interrupt re-entered\n", host->host->host_no);
+       printk("scsi%d: interrupt re-entered\n", host->host->host_no);
     host->scsi.interrupt = 1;
 
     do {
        ret = INTR_IDLE;
 
-       iostatus = inb (host->card.io_intr);
+       iostatus = inb(host->card.io_intr);
 
        if (iostatus & 2) {
-           acornscsi_dma_intr (host);
-           iostatus = inb (host->card.io_intr);
+           acornscsi_dma_intr(host);
+           iostatus = inb(host->card.io_intr);
        }
 
        if (iostatus & 8)
-           ret = acornscsi_sbicintr (host, in_irq);
+           ret = acornscsi_sbicintr(host, in_irq);
 
        /*
         * If we have a transfer pending, start it.
@@ -2382,10 +2505,10 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
         * it's data
         */
        if (host->dma.xfer_required)
-           acornscsi_dma_xfer (host);
+           acornscsi_dma_xfer(host);
 
        if (ret == INTR_NEXT_COMMAND)
-           ret = acornscsi_kick (host);
+           ret = acornscsi_kick(host);
 
        in_irq = 1;
     } while (ret != INTR_IDLE);
@@ -2398,29 +2521,29 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
  */
 
 /*
- * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
  * Purpose  : queues a SCSI command
  * Params   : cmd  - SCSI command
  *           done - function called on completion, with pointer to command descriptor
  * Returns  : 0, or < 0 on error.
  */
-int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
     AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
 
     if (!done) {
        /* there should be some way of rejecting errors like this without panicing... */
-       panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]",
+       panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
                SCpnt->host->host_no, SCpnt);
        return -EINVAL;
     }
 
 #if (DEBUG & DEBUG_NO_WRITE)
-    if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) {
-       printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
+    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) {
+       printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
            SCpnt->host->host_no, '0' + SCpnt->target);
        SCpnt->result = DID_NO_CONNECT << 16;
-       done (SCpnt);
+       done(SCpnt);
        return 0;
     }
 #endif
@@ -2429,7 +2552,7 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
     SCpnt->host_scribble = NULL;
     SCpnt->result = 0;
     SCpnt->tag = 0;
-    SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]);
+    SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
     SCpnt->SCp.sent_command = 0;
     SCpnt->SCp.scsi_xferred = 0;
     SCpnt->SCp.Status = 0;
@@ -2452,21 +2575,21 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
     {
        unsigned long flags;
 
-       if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) {
+       if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
            SCpnt->result = DID_ERROR << 16;
-           done (SCpnt);
+           done(SCpnt);
            return 0;
        }
-       save_flags_cli (flags);
+       save_flags_cli(flags);
        if (host->scsi.phase == PHASE_IDLE)
-           acornscsi_kick (host);
-       restore_flags (flags);
+           acornscsi_kick(host);
+       restore_flags(flags);
     }
     return 0;
 }
 
 /*
- * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
  * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
  * Params   : SCpntp1 - pointer to command to return
  *           SCpntp2 - pointer to command to check
@@ -2474,7 +2597,7 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
  * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
  */
 static inline
-void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
 {
     Scsi_Cmnd *SCpnt = *SCpntp1;
 
@@ -2482,80 +2605,203 @@ void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int resul
        *SCpntp1 = NULL;
 
        SCpnt->result = result;
-       SCpnt->scsi_done (SCpnt);
+       SCpnt->scsi_done(SCpnt);
     }
 
     if (SCpnt == *SCpntp2)
        *SCpntp2 = NULL;
 }
 
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
 /*
- * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt)
+ * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
  * Purpose  : abort a command on this host
  * Params   : SCpnt - command to abort
- * Returns  : one of SCSI_ABORT_ macros
+ * Returns  : our abort status
  */
-int acornscsi_abort (Scsi_Cmnd *SCpnt)
+static enum res_abort
+acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
 {
-    AS_Host *host = (AS_Host *) SCpnt->host->hostdata;
-    int result = SCSI_ABORT_NOT_RUNNING;
+       enum res_abort res = res_not_running;
 
-    host->stats.aborts += 1;
+       if (queue_removecmd(&host->queues.issue, SCpnt)) {
+               /*
+                * The command was on the issue queue, and has not been
+                * issued yet.  We can remove the command from the queue,
+                * and acknowledge the abort.  Neither the devices nor the
+                * interface know about the command.
+                */
+//#if (DEBUG & DEBUG_ABORT)
+               printk("on issue queue ");
+//#endif
+               res = res_success;
+       } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) {
+               /*
+                * The command was on the disconnected queue.  Simply
+                * acknowledge the abort condition, and when the target
+                * reconnects, we will give it an ABORT message.  The
+                * target should then disconnect, and we will clear
+                * the busylun bit.
+                */
+//#if (DEBUG & DEBUG_ABORT)
+               printk("on disconnected queue ");
+//#endif
+               res = res_success;
+       } else if (host->SCpnt == SCpnt) {
+               unsigned long flags;
+
+//#if (DEBUG & DEBUG_ABORT)
+               printk("executing ");
+//#endif
+
+               save_flags(flags);
+               cli();
+               switch (host->scsi.phase) {
+               /*
+                * If the interface is idle, and the command is 'disconnectable',
+                * then it is the same as on the disconnected queue.  We simply
+                * remove all traces of the command.  When the target reconnects,
+                * we will give it an ABORT message since the command could not
+                * be found.  When the target finally disconnects, we will clear
+                * the busylun bit.
+                */
+               case PHASE_IDLE:
+                       if (host->scsi.disconnectable) {
+                               host->scsi.disconnectable = 0;
+                               host->SCpnt = NULL;
+                               res = res_success;
+                       }
+                       break;
 
-#if (DEBUG & DEBUG_ABORT)
-    {
-       int asr, ssr;
-       asr = sbic_arm_read (host->scsi.io_port, ASR);
-       ssr = sbic_arm_read (host->scsi.io_port, SSR);
+               /*
+                * If the command has connected and done nothing further,
+                * simply force a disconnect.  We also need to clear the
+                * busylun bit.
+                */
+               case PHASE_CONNECTED:
+                       sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT);
+                       host->SCpnt = NULL;
+                       res = res_success_clear;
+                       break;
+
+               default:
+                       acornscsi_abortcmd(host, host->SCpnt->tag);
+                       res = res_snooze;
+               }
+               restore_flags(flags);
+       } else if (host->origSCpnt == SCpnt) {
+               /*
+                * The command will be executed next, but a command
+                * is currently using the interface.  This is similar to
+                * being on the issue queue, except the busylun bit has
+                * been set.
+                */
+               host->origSCpnt = NULL;
+//#if (DEBUG & DEBUG_ABORT)
+               printk("waiting for execution ");
+//#endif
+               res = res_success_clear;
+       } else
+               printk("unknown ");
 
-       printk (KERN_WARNING "acornscsi_abort: ");
-       print_sbic_status(asr, ssr, host->scsi.phase);
-       acornscsi_dumplog (host, SCpnt->target);
-    }
-#endif
+       return res;
+}
+
+/*
+ * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : one of SCSI_ABORT_ macros
+ */
+int acornscsi_abort(Scsi_Cmnd *SCpnt)
+{
+       AS_Host *host = (AS_Host *) SCpnt->host->hostdata;
+       int result;
+
+       host->stats.aborts += 1;
 
-    if (queue_removecmd (&host->queues.issue, SCpnt)) {
-       SCpnt->result = DID_ABORT << 16;
-       SCpnt->scsi_done (SCpnt);
-#if (DEBUG & DEBUG_ABORT)
-       printk ("scsi%d: command on issue queue\n", host->host->host_no);
-#endif
-       result = SCSI_ABORT_SUCCESS;
-    } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) {
-       printk ("scsi%d: command on disconnected queue\n", host->host->host_no);
-       result = SCSI_ABORT_SNOOZE;
-    } else if (host->SCpnt == SCpnt) {
-       acornscsi_abortcmd (host, host->SCpnt->tag);
-       printk ("scsi%d: command executing\n", host->host->host_no);
-       result = SCSI_ABORT_SNOOZE;
-    } else if (host->origSCpnt == SCpnt) {
-       host->origSCpnt = NULL;
-       SCpnt->result = DID_ABORT << 16;
-       SCpnt->scsi_done (SCpnt);
 #if (DEBUG & DEBUG_ABORT)
-       printk ("scsi%d: command waiting for execution\n", host->host->host_no);
+       {
+               int asr, ssr;
+               asr = sbic_arm_read(host->scsi.io_port, ASR);
+               ssr = sbic_arm_read(host->scsi.io_port, SSR);
+
+               printk(KERN_WARNING "acornscsi_abort: ");
+               print_sbic_status(asr, ssr, host->scsi.phase);
+               acornscsi_dumplog(host, SCpnt->target);
+       }
 #endif
-       result = SCSI_ABORT_SUCCESS;
-    }
 
-    if (result == SCSI_ABORT_NOT_RUNNING) {
-       printk ("scsi%d: abort(): command not running\n", host->host->host_no);
-       acornscsi_dumplog (host, SCpnt->target);
+       printk("scsi%d: ", host->host->host_no);
+
+       switch (acornscsi_do_abort(host, SCpnt)) {
+       /*
+        * We managed to find the command and cleared it out.
+        * We do not expect the command to be executing on the
+        * target, but we have set the busylun bit.
+        */
+       case res_success_clear:
+//#if (DEBUG & DEBUG_ABORT)
+               printk("clear ");
+//#endif
+               clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+
+       /*
+        * We found the command, and cleared it out.  Either
+        * the command is still known to be executing on the
+        * target, or the busylun bit is not set.
+        */
+       case res_success:
+//#if (DEBUG & DEBUG_ABORT)
+               printk("success\n");
+//#endif
+               SCpnt->result = DID_ABORT << 16;
+               SCpnt->scsi_done(SCpnt);
+               result = SCSI_ABORT_SUCCESS;
+               break;
+
+       /*
+        * We did find the command, but unfortunately we couldn't
+        * unhook it from ourselves.  Wait some more, and if it
+        * still doesn't complete, reset the interface.
+        */
+       case res_snooze:
+//#if (DEBUG & DEBUG_ABORT)
+               printk("snooze\n");
+//#endif
+               result = SCSI_ABORT_SNOOZE;
+               break;
+
+       /*
+        * The command could not be found (either because it completed,
+        * or it got dropped.
+        */
+       default:
+       case res_not_running:
+               acornscsi_dumplog(host, SCpnt->target);
 #if (DEBUG & DEBUG_ABORT)
-       result = SCSI_ABORT_SNOOZE;
+               result = SCSI_ABORT_SNOOZE;
+#else
+               result = SCSI_ABORT_NOT_RUNNING;
 #endif
-    }
-    return result;
+//#if (DEBUG & DEBUG_ABORT)
+               printk("not running\n");
+//#endif
+               break;
+       }
+
+       return result;
 }
 
 /*
- * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
  * Purpose  : reset a command on this host/reset this host
  * Params   : SCpnt  - command causing reset
  *           result - what type of reset to perform
  * Returns  : one of SCSI_RESET_ macros
  */
-int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
 {
     AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
     Scsi_Cmnd *SCptr;
@@ -2566,16 +2812,16 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
     {
        int asr, ssr;
 
-       asr = sbic_arm_read (host->scsi.io_port, ASR);
-       ssr = sbic_arm_read (host->scsi.io_port, SSR);
+       asr = sbic_arm_read(host->scsi.io_port, ASR);
+       ssr = sbic_arm_read(host->scsi.io_port, SSR);
 
-       printk (KERN_WARNING "acornscsi_reset: ");
+       printk(KERN_WARNING "acornscsi_reset: ");
        print_sbic_status(asr, ssr, host->scsi.phase);
-       acornscsi_dumplog (host, SCpnt->target);
+       acornscsi_dumplog(host, SCpnt->target);
     }
 #endif
 
-    acornscsi_dma_stop (host);
+    acornscsi_dma_stop(host);
 
     SCptr = host->SCpnt;
 
@@ -2583,19 +2829,19 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
      * do hard reset.  This resets all devices on this host, and so we
      * must set the reset status on all commands.
      */
-    acornscsi_resetcard (host);
+    acornscsi_resetcard(host);
 
     /*
      * report reset on commands current connected/disconnected
      */
-    acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET);
+    acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET);
 
-    while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL)
-       acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET);
+    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
+       acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET);
 
     if (SCpnt) {
        SCpnt->result = DID_RESET << 16;
-       SCpnt->scsi_done (SCpnt);
+       SCpnt->scsi_done(SCpnt);
     }
 
     return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
@@ -2607,19 +2853,19 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
 static struct expansion_card *ecs[MAX_ECARDS];
 
 /*
- * Prototype: void acornscsi_init (AS_Host *host)
+ * Prototype: void acornscsi_init(AS_Host *host)
  * Purpose  : initialise the AS_Host structure for one interface & setup hardware
  * Params   : host - host to setup
  */
 static
-void acornscsi_init (AS_Host *host)
+void acornscsi_init(AS_Host *host)
 {
-    memset (&host->stats, 0, sizeof (host->stats));
-    queue_initialise (&host->queues.issue);
-    queue_initialise (&host->queues.disconnected);
-    msgqueue_initialise (&host->scsi.msgs);
+    memset(&host->stats, 0, sizeof (host->stats));
+    queue_initialise(&host->queues.issue);
+    queue_initialise(&host->queues.disconnected);
+    msgqueue_initialise(&host->scsi.msgs);
 
-    acornscsi_resetcard (host);
+    acornscsi_resetcard(host);
 }
 
 int acornscsi_detect(Scsi_Host_Template * tpnt)
@@ -2634,7 +2880,7 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
     for (i = 0; i < MAX_ECARDS; i++)
        ecs[i] = NULL;
 
-    ecard_startfind ();
+    ecard_startfind();
 
     while(1) {
        ecs[count] = ecard_find(0, acornscsi_cids);
@@ -2642,37 +2888,37 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
            break;
 
        if (ecs[count]->irq == 0xff) {
-           printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n");
+           printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n");
            continue;
        }
 
        ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */
 
-       instance = scsi_register (tpnt, sizeof(AS_Host));
+       instance = scsi_register(tpnt, sizeof(AS_Host));
        host = (AS_Host *)instance->hostdata;
 
-       instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0);
+       instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0);
        instance->irq = ecs[count]->irq;
 
        host->host              = instance;
-       host->scsi.io_port      = ioaddr (instance->io_port + 0x800);
+       host->scsi.io_port      = ioaddr(instance->io_port + 0x800);
        host->scsi.irq          = instance->irq;
        host->card.io_intr      = POD_SPACE(instance->io_port) + 0x800;
        host->card.io_page      = POD_SPACE(instance->io_port) + 0xc00;
-       host->card.io_ram       = ioaddr (instance->io_port);
+       host->card.io_ram       = ioaddr(instance->io_port);
        host->dma.io_port       = instance->io_port + 0xc00;
        host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800;
 
        ecs[count]->irqaddr     = (char *)ioaddr(host->card.io_intr);
        ecs[count]->irqmask     = 0x0a;
 
-       request_region (instance->io_port + 0x800,  2, "acornscsi(sbic)");
-       request_region (host->card.io_intr,  1, "acornscsi(intr)");
-       request_region (host->card.io_page,  1, "acornscsi(page)");
+       request_region(instance->io_port + 0x800,  2, "acornscsi(sbic)");
+       request_region(host->card.io_intr,  1, "acornscsi(intr)");
+       request_region(host->card.io_page,  1, "acornscsi(page)");
 #ifdef USE_DMAC
-       request_region (host->dma.io_port, 256, "acornscsi(dmac)");
+       request_region(host->dma.io_port, 256, "acornscsi(dmac)");
 #endif
-       request_region (instance->io_port, 2048, "acornscsi(ram)");
+       request_region(instance->io_port, 2048, "acornscsi(ram)");
 
        if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) {
            printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n",
@@ -2680,7 +2926,7 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
            host->scsi.irq = NO_IRQ;
        }
 
-       acornscsi_init (host);
+       acornscsi_init(host);
 
        ++count;
     }
@@ -2688,12 +2934,12 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
 }
 
 /*
- * Function: int acornscsi_release (struct Scsi_Host *host)
+ * Function: int acornscsi_release(struct Scsi_Host *host)
  * Purpose : release all resources used by this adapter
  * Params  : host - driver structure to release
  * Returns : nothing of any consequence
  */
-int acornscsi_release (struct Scsi_Host *instance)
+int acornscsi_release(struct Scsi_Host *instance)
 {
     AS_Host *host = (AS_Host *)instance->hostdata;
     int i;
@@ -2701,30 +2947,30 @@ int acornscsi_release (struct Scsi_Host *instance)
     /*
      * Put card into RESET state
      */
-    outb (0x80, host->card.io_page);
+    outb(0x80, host->card.io_page);
 
     if (host->scsi.irq != NO_IRQ)
-       free_irq (host->scsi.irq, host);
+       free_irq(host->scsi.irq, host);
 
-    release_region (instance->io_port + 0x800, 2);
-    release_region (host->card.io_intr, 1);
-    release_region (host->card.io_page, 1);
-    release_region (host->dma.io_port, 256);
-    release_region (instance->io_port, 2048);
+    release_region(instance->io_port + 0x800, 2);
+    release_region(host->card.io_intr, 1);
+    release_region(host->card.io_page, 1);
+    release_region(host->dma.io_port, 256);
+    release_region(instance->io_port, 2048);
 
     for (i = 0; i < MAX_ECARDS; i++)
-       if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0))
-           ecard_release (ecs[i]);
+       if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0))
+           ecard_release(ecs[i]);
 
-    msgqueue_free (&host->scsi.msgs);
-    queue_free (&host->queues.disconnected);
-    queue_free (&host->queues.issue);
+    msgqueue_free(&host->scsi.msgs);
+    queue_free(&host->queues.disconnected);
+    queue_free(&host->queues.issue);
 
     return 0;
 }
 
 /*
- * Function: char *acornscsi_info (struct Scsi_Host *host)
+ * Function: char *acornscsi_info(struct Scsi_Host *host)
  * Purpose : return a string describing this interface
  * Params  : host - host to give information on
  * Returns : a constant string
@@ -2736,7 +2982,7 @@ char *acornscsi_info(struct Scsi_Host *host)
 
     p = string;
     
-    p += sprintf (string, "%s at port %lX irq %d v%d.%d.%d"
+    p += sprintf(string, "%s at port %X irq %d v%d.%d.%d"
 #ifdef CONFIG_SCSI_ACORNSCSI_SYNC
     " SYNC"
 #endif
@@ -2772,7 +3018,7 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
 
     host  = (AS_Host *)instance->hostdata;
     
-    p += sprintf (p, "AcornSCSI driver v%d.%d.%d"
+    p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
 #ifdef CONFIG_SCSI_ACORNSCSI_SYNC
     " SYNC"
 #endif
@@ -2787,14 +3033,14 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
 #endif
                "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
 
-    p += sprintf (p,   "SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
+    p += sprintf(p,    "SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
                        host->scsi.io_port, host->scsi.irq);
 #ifdef USE_DMAC
-    p += sprintf (p,   "DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
+    p += sprintf(p,    "DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
                        host->dma.io_port, host->scsi.irq);
 #endif
 
-    p += sprintf (p,   "Statistics:\n"
+    p += sprintf(p,    "Statistics:\n"
                        "Queued commands: %-10u    Issued commands: %-10u\n"
                        "Done commands  : %-10u    Reads          : %-10u\n"
                        "Writes         : %-10u    Others         : %-10u\n"
@@ -2809,47 +3055,47 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
     for (devidx = 0; devidx < 9; devidx ++) {
        unsigned int statptr, prev;
 
-       p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
-       statptr = status_ptr[devidx] - 10;
+       p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
+       statptr = host->status_ptr[devidx] - 10;
 
        if ((signed int)statptr < 0)
-           statptr += 16;
-
-       prev = status[devidx][statptr].when;
-
-       for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) {
-           if (status[devidx][statptr].when) {
-               p += sprintf (p, "%c%02X:%02X+%2ld",
-                       status[devidx][statptr].irq ? '-' : ' ',
-                       status[devidx][statptr].ph,
-                       status[devidx][statptr].ssr,
-                       (status[devidx][statptr].when - prev) < 100 ?
-                               (status[devidx][statptr].when - prev) : 99);
-               prev = status[devidx][statptr].when;
+           statptr += STATUS_BUFFER_SIZE;
+
+       prev = host->status[devidx][statptr].when;
+
+       for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+           if (host->status[devidx][statptr].when) {
+               p += sprintf(p, "%c%02X:%02X+%2ld",
+                       host->status[devidx][statptr].irq ? '-' : ' ',
+                       host->status[devidx][statptr].ph,
+                       host->status[devidx][statptr].ssr,
+                       (host->status[devidx][statptr].when - prev) < 100 ?
+                               (host->status[devidx][statptr].when - prev) : 99);
+               prev = host->status[devidx][statptr].when;
            }
        }
     }
 
-    p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none");
+    p += sprintf(p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none");
 
     for (scd = instance->host_queue; scd; scd = scd->next) {
        int len;
 
-       proc_print_scsidevice (scd, p, &len, 0);
+       proc_print_scsidevice(scd, p, &len, 0);
        p += len;
 
-       p += sprintf (p, "Extensions: ");
+       p += sprintf(p, "Extensions: ");
 
        if (scd->tagged_supported)
-           p += sprintf (p, "TAG %sabled [%d] ",
+           p += sprintf(p, "TAG %sabled [%d] ",
                          scd->tagged_queue ? "en" : "dis", scd->current_tag);
-       p += sprintf (p, "\nTransfers: ");
+       p += sprintf(p, "\nTransfers: ");
        if (host->device[scd->id].sync_xfer & 15)
-           p += sprintf (p, "sync, offset %d, %d ns\n",
+           p += sprintf(p, "sync, offset %d, %d ns\n",
                          host->device[scd->id].sync_xfer & 15,
-                         acornscsi_getperiod (host->device[scd->id].sync_xfer));
+                         acornscsi_getperiod(host->device[scd->id].sync_xfer));
        else
-           p += sprintf (p, "async\n");
+           p += sprintf(p, "async\n");
 
        pos = p - buffer;
        if (pos + begin < offset) {
index ffaba7c2cb7a7938b752a8d4aaf66e2331c83ba2..5470c6b6cdca5ade09b5ae4cfd6e3a00af62164a 100644 (file)
@@ -291,6 +291,27 @@ typedef enum {                                     /* Data direction                       */
 #include "queue.h"
 #include "msgqueue.h"
 
+#define STATUS_BUFFER_SIZE     32
+/*
+ * This is used to dump the previous states of the SBIC
+ */
+struct status_entry {
+       unsigned long   when;
+       unsigned char   ssr;
+       unsigned char   ph;
+       unsigned char   irq;
+       unsigned char   unused;
+};
+
+#define ADD_STATUS(_q,_ssr,_ph,_irq) \
+({                                                                     \
+       host->status[(_q)][host->status_ptr[(_q)]].when = jiffies;      \
+       host->status[(_q)][host->status_ptr[(_q)]].ssr  = (_ssr);       \
+       host->status[(_q)][host->status_ptr[(_q)]].ph   = (_ph);        \
+       host->status[(_q)][host->status_ptr[(_q)]].irq  = (_irq);       \
+       host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \
+})
+
 /*
  * AcornSCSI host specific data
  */
@@ -303,7 +324,7 @@ typedef struct acornscsi_hostdata {
     /* driver information */
     struct {
        unsigned int    io_port;                /* base address of WD33C93              */
-       unsigned char   irq;                    /* interrupt                            */
+       unsigned int    irq;                    /* interrupt                            */
        phase_t         phase;                  /* current phase                        */
 
        struct {
@@ -361,6 +382,7 @@ typedef struct acornscsi_hostdata {
        char            *xfer_ptr;              /* pointer to area                      */
        unsigned char   xfer_required:1;        /* set if we need to transfer something */
        unsigned char   xfer_setup:1;           /* set if DMA is setup                  */
+       unsigned char   xfer_done:1;            /* set if DMA reached end of BH list    */
     } dma;
 
     /* card info */
@@ -370,6 +392,9 @@ typedef struct acornscsi_hostdata {
        unsigned int    io_ram;                 /* base address of RAM access           */
        unsigned char   page_reg;               /* current setting of page reg          */
     } card;
+
+    unsigned char status_ptr[9];
+    struct status_entry status[9][STATUS_BUFFER_SIZE];
 } AS_Host;
 
 #endif /* ndef HOSTS_C */
diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
new file mode 100644 (file)
index 0000000..4afebe3
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * linux/arch/arm/drivers/scsi/cumana_2.c
+ *
+ * Copyright (C) 1997,1998 Russell King
+ *
+ * This driver is based on experimentation.  Hence, it may have made
+ * assumptions about the particular card that I have available, and
+ * may not be reliable!
+ *
+ * Changelog:
+ *  30-08-1997 RMK     0.0.0   Created, READONLY version as cumana_2.c
+ *  22-01-1998 RMK     0.0.1   Updated to 2.1.80
+ *  15-04-1998 RMK     0.0.1   Only do PIO if FAS216 will allow it.
+ *  11-06-1998                 0.0.2   Changed to support ARXE 16-bit SCSI card, enabled writing
+ *                             by Stefan Hanske
+ */
+
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+
+#include <asm/delay.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../../scsi/sd.h"
+#include "../../scsi/hosts.h"
+#include "arxescsi.h"
+#include "fas216.h"
+
+/* Hmm - this should go somewhere else */
+#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+
+/* Configuration */
+#define ARXESCSI_XTALFREQ              24
+#define ARXESCSI_ASYNC_PERIOD          200
+#define ARXESCSI_SYNC_DEPTH            0
+
+/*
+ * List of devices that the driver will recognise
+ */
+#define ARXESCSI_LIST          { MANU_ARXE, PROD_ARXE_SCSI }
+
+/*
+ * Version
+ */
+#define VER_MAJOR      0
+#define VER_MINOR      0
+#define VER_PATCH      2
+
+static struct expansion_card *ecs[MAX_ECARDS];
+
+static struct proc_dir_entry proc_scsi_arxescsi = {
+       PROC_SCSI_QLOGICFAS, 6, "arxescsi",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/*
+ * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose : initialises DMA/PIO
+ * Params  : host      - host
+ *          SCpnt     - command
+ *          direction - DMA on to/off of card
+ *          min_type  - minimum DMA support that we must have for this transfer
+ * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
+ */
+static fasdmatype_t
+arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+                      fasdmadir_t direction, fasdmatype_t min_type)
+{
+       /*
+        * We don't do real DMA
+        */
+       return fasdma_pseudo;
+}
+
+
+
+/* Faster transfer routines, written by SH to speed up the loops */
+
+static __inline__ unsigned char getb(unsigned int address, unsigned int reg)
+{
+       unsigned char value;
+
+       __asm__ __volatile__(
+       "ldrb   %0, [%1, %2, lsl #5]"
+       : "=r" (value)
+       : "r" (address), "r" (reg) );
+       return value;
+}
+
+static __inline__ unsigned int getw(unsigned int address, unsigned int reg)
+{
+       unsigned int value;
+       
+       __asm__ __volatile__(
+       "ldr    %0, [%1, %2, lsl #5]\n\t"
+       "mov    %0, %0, lsl #16\n\t"
+       "mov    %0, %0, lsr #16"
+       : "=r" (value)
+       : "r" (address), "r" (reg) );
+       return value;
+}
+
+static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value)
+{
+       __asm__ __volatile__(
+       "mov    %0, %0, lsl #16\n\t"
+       "str    %0, [%1, %2, lsl #5]"
+       :
+       : "r" (value), "r" (address), "r" (reg) );
+}
+
+
+/*
+ * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose : handles pseudo DMA
+ * Params  : host      - host
+ *          SCpnt     - command
+ *          direction - DMA on to/off of card
+ *          transfer  - minimum number of bytes we expect to transfer
+ */
+void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+                       fasdmadir_t direction, int transfer)
+{
+       ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata;
+       unsigned int length, io, error=0;
+       unsigned char *addr;
+
+       length = SCp->this_residual;
+       addr = SCp->ptr;
+       io = __ioaddr(host->io_port);
+
+       if (direction == DMA_OUT) {
+               while (length > 0) {
+                       unsigned long word;
+
+
+                       word = *addr | *(addr + 1) << 8;
+                       if (getb(io, 4) & STAT_INT)
+                               break;
+
+                       if (!(getb(io, 48) & CSTATUS_IRQ))
+                               continue;
+
+                       putw(io, 16, word);
+                       if (length > 1) {
+                               addr += 2;
+                               length -= 2;
+                       } else {
+                               addr += 1;
+                               length -= 1;
+                       }
+               }
+       }
+       else {
+               if (transfer && (transfer & 255)) {
+                       while (length >= 256) {
+                               if (getb(io, 4) & STAT_INT) {
+                                       error=1;
+                                       break;
+                               }
+           
+                               if (!(getb(io, 48) & CSTATUS_IRQ))
+                                       continue;
+
+                               insw(info->dmaarea, addr, 256 >> 1);
+                               addr += 256;
+                               length -= 256;
+                       }
+               }
+
+               if (!(error))
+                       while (length > 0) {
+                               unsigned long word;
+
+                               if (getb(io, 4) & STAT_INT)
+                                       break;
+
+                               if (!(getb(io, 48) & CSTATUS_IRQ))
+                                       continue;
+
+                               word = getw(io, 16);
+                               *addr++ = word;
+                               if (--length > 0) {
+                                       *addr++ = word >> 8;
+                                       length --;
+                               }
+                       }
+       }
+}
+
+/*
+ * Function: int arxescsi_dma_stop(host, SCpnt)
+ * Purpose : stops DMA/PIO
+ * Params  : host  - host
+ *          SCpnt - command
+ */
+static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+       /*
+        * no DMA to stop
+        */
+}
+
+/*
+ * Function: int arxescsi_detect(Scsi_Host_Template * tpnt)
+ * Purpose : initialises ARXE SCSI driver
+ * Params  : tpnt - template for this SCSI adapter
+ * Returns : >0 if host found, 0 otherwise.
+ */
+int arxescsi_detect(Scsi_Host_Template *tpnt)
+{
+       static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} };
+       int count = 0;
+       struct Scsi_Host *host;
+  
+       tpnt->proc_dir = &proc_scsi_arxescsi;
+       memset(ecs, 0, sizeof (ecs));
+
+       ecard_startfind();
+
+       while (1) {
+               ARXEScsi_Info *info;
+
+               ecs[count] = ecard_find(0, arxescsi_cids);
+               if (!ecs[count])
+                       break;
+
+               ecard_claim(ecs[count]);
+               
+               host = scsi_register(tpnt, sizeof (ARXEScsi_Info));
+               if (!host) {
+                       ecard_release(ecs[count]);
+                       break;
+               }
+
+               host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0) + 0x0800;
+               host->irq = NO_IRQ;
+               host->dma_channel = NO_DMA;
+               host->can_queue = 0; /* no command queueing */
+               info = (ARXEScsi_Info *)host->hostdata;
+
+               info->info.scsi.io_port         = host->io_port;
+               info->info.scsi.irq             = host->irq;
+               info->info.scsi.io_shift        = 3;
+               info->info.ifcfg.clockrate      = ARXESCSI_XTALFREQ;
+               info->info.ifcfg.select_timeout = 255;
+               info->info.ifcfg.asyncperiod    = ARXESCSI_ASYNC_PERIOD;
+               info->info.ifcfg.sync_max_depth = ARXESCSI_SYNC_DEPTH;
+               info->info.ifcfg.cntl3          = CNTL3_FASTSCSI | CNTL3_FASTCLK;
+               info->info.ifcfg.disconnect_ok  = 0;
+               info->info.ifcfg.wide_max_size  = 0;
+               info->info.dma.setup            = arxescsi_dma_setup;
+               info->info.dma.pseudo           = arxescsi_dma_pseudo;
+               info->info.dma.stop             = arxescsi_dma_stop;
+               info->dmaarea                   = host->io_port + 128;
+               info->cstatus                   = host->io_port + 384;
+               
+               ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port);
+               ecs[count]->irqmask = CSTATUS_IRQ;
+
+               request_region(host->io_port      , 120, "arxescsi-fas");
+               request_region(host->io_port + 128, 384, "arxescsi-dma");
+
+               printk("scsi%d: Has no interrupts - using polling mode\n",
+                      host->host_no);
+
+               fas216_init(host);
+               ++count;
+       }
+       return count;
+}
+
+/*
+ * Function: int arxescsi_release(struct Scsi_Host * host)
+ * Purpose : releases all resources used by this adapter
+ * Params  : host - driver host structure to return info for.
+ * Returns : nothing
+ */
+int arxescsi_release(struct Scsi_Host *host)
+{
+       int i;
+
+       fas216_release(host);
+
+       release_region(host->io_port, 120);
+       release_region(host->io_port + 128, 384);
+
+       for (i = 0; i < MAX_ECARDS; i++)
+               if (ecs[i] && host->io_port == (ecard_address(ecs[i], ECARD_MEMC, 0) + 0x0800))
+                       ecard_release(ecs[i]);
+       return 0;
+}
+
+/*
+ * Function: const char *arxescsi_info(struct Scsi_Host * host)
+ * Purpose : returns a descriptive string about this interface,
+ * Params  : host - driver host structure to return info for.
+ * Returns : pointer to a static buffer containing null terminated string.
+ */
+const char *arxescsi_info(struct Scsi_Host *host)
+{
+       ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata;
+       static char string[100], *p;
+
+       p = string;
+       p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s",
+                    host->hostt->name, host->io_port, host->irq,
+                    VER_MAJOR, VER_MINOR, VER_PATCH,
+                    info->info.scsi.type);
+
+       return string;
+}
+
+/*
+ * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+ *                                      int length, int host_no, int inout)
+ * Purpose : Return information about the driver to a user process accessing
+ *          the /proc filesystem.
+ * Params  : buffer - a buffer to write information to
+ *          start  - a pointer into this buffer set by this routine to the start
+ *                   of the required information.
+ *          offset - offset into information that we have read upto.
+ *          length - length of buffer
+ *          host_no - host number to return information for
+ *          inout  - 0 for reading, 1 for writing.
+ * Returns : length of data written to buffer.
+ */
+int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+                           int length, int host_no, int inout)
+{
+       int pos, begin;
+       struct Scsi_Host *host = scsi_hostlist;
+       ARXEScsi_Info *info;
+       Scsi_Device *scd;
+
+       while (host) {
+               if (host->host_no == host_no)
+                       break;
+               host = host->next;
+       }
+       if (!host)
+               return 0;
+
+       info = (ARXEScsi_Info *)host->hostdata;
+       if (inout == 1)
+               return -EINVAL;
+
+       begin = 0;
+       pos = sprintf(buffer,
+                       "ARXE 16-bit SCSI driver version %d.%d.%d\n",
+                       VER_MAJOR, VER_MINOR, VER_PATCH);
+       pos += sprintf(buffer + pos,
+                       "Address: %08lX          IRQ : %d\n"
+                       "FAS    : %s\n\n"
+                       "Statistics:\n",
+                       host->io_port, host->irq, info->info.scsi.type);
+
+       pos += fas216_print_stats(&info->info, buffer + pos);
+
+       pos += sprintf (buffer+pos, "\nAttached devices:\n");
+
+       for (scd = host->host_queue; scd; scd = scd->next) {
+               pos += fas216_print_device(&info->info, scd, buffer + pos);
+
+               if (pos + begin < offset) {
+                       begin += pos;
+                       pos = 0;
+               }
+               if (pos + begin > offset + length)
+                       break;
+       }
+
+       *start = buffer + (offset - begin);
+       pos -= offset - begin;
+       if (pos > length)
+               pos = length;
+
+       return pos;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ARXEScsi;
+
+#include "../../scsi/scsi_module.c"
+#endif
diff --git a/drivers/acorn/scsi/arxescsi.h b/drivers/acorn/scsi/arxescsi.h
new file mode 100644 (file)
index 0000000..11dc6b6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * ARXE SCSI card driver
+ *
+ * Copyright (C) 1997 Russell King
+ * Changes to support ARXE 16-bit SCSI card by Stefan Hanske
+ */
+#ifndef ARXE_SCSI_H
+#define ARXE_SCSI_H
+
+#define MANU_ARXE      0x0041
+#define PROD_ARXE_SCSI 0x00be
+
+extern int arxescsi_detect (Scsi_Host_Template *);
+extern int arxescsi_release (struct Scsi_Host *);
+extern const char *arxescsi_info (struct Scsi_Host *);
+extern int arxescsi_proc_info (char *buffer, char **start, off_t offset,
+                               int length, int hostno, int inout);
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#ifndef CAN_QUEUE
+/*
+ * Default queue size
+ */
+#define CAN_QUEUE      1
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN    1
+#endif
+
+#ifndef SCSI_ID
+/*
+ * Default SCSI host ID
+ */
+#define SCSI_ID                7
+#endif
+
+#include <scsi/scsicam.h>
+
+#ifndef HOSTS_C
+#include "fas216.h"
+#endif
+
+#define ARXEScsi {                                                     \
+proc_info:     arxescsi_proc_info,                                             \
+name:          "ARXE SCSI card",                                               \
+detect:                arxescsi_detect,                /* detect               */      \
+release:       arxescsi_release,               /* release              */      \
+info:          arxescsi_info,                  /* info                 */      \
+command:       fas216_command,                 /* command              */      \
+queuecommand:  fas216_queue_command,           /* queuecommand         */      \
+abort:         fas216_abort,                   /* abort                */      \
+reset:         fas216_reset,                   /* reset                */      \
+bios_param:    scsicam_bios_param,             /* biosparam            */      \
+can_queue:     CAN_QUEUE,                      /* can queue            */      \
+this_id:       SCSI_ID,                        /* scsi host id         */      \
+sg_tablesize:  SG_ALL,                         /* sg_tablesize         */      \
+cmd_per_lun:   CMD_PER_LUN,                    /* cmd per lun          */      \
+use_clustering:        DISABLE_CLUSTERING                                              \
+       }
+
+#ifndef HOSTS_C
+
+typedef struct {
+    FAS216_Info info;
+
+    /* other info... */
+    unsigned int       cstatus;        /* card status register */
+    unsigned int       dmaarea;        /* Pseudo DMA area      */
+} ARXEScsi_Info;
+
+#define CSTATUS_IRQ    (1 << 0)
+#define CSTATUS_DRQ    (1 << 0)
+
+#endif /* HOSTS_C */
+
+#endif /* ARXE_SCSI_H */
index 797eaae066d9ca611e232b2e78249ece35656c3c..c0edf3b645d5a23c6f551f7a6a921b1eb0847106 100644 (file)
@@ -4,12 +4,12 @@
  * Copyright (C) 1997-1998 Russell King
  *
  * Changelog:
- *  30-08-1997 RMK     0.0.0   Created, READONLY version
- *  22-01-1998 RMK     0.0.1   Updated to 2.1.80
+ *  30-08-1997 RMK     0.0.0   Created, READONLY version.
+ *  22-01-1998 RMK     0.0.1   Updated to 2.1.80.
  *  15-04-1998 RMK     0.0.1   Only do PIO if FAS216 will allow it.
- *  02-05-1998 RMK     0.0.2   Updated & added DMA support
+ *  02-05-1998 RMK     0.0.2   Updated & added DMA support.
  *  27-06-1998 RMK             Changed asm/delay.h to linux/delay.h
- *  18-08-1998 RMK     0.0.3   Fixed synchronous transfer depth
+ *  18-08-1998 RMK     0.0.3   Fixed synchronous transfer depth.
  */
 
 #include <linux/module.h>
@@ -117,6 +117,8 @@ static const expansioncard_ops_t cumanascsi_2_ops = {
        cumanascsi_2_irqenable,
        cumanascsi_2_irqdisable,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
@@ -364,6 +366,7 @@ cumanascsi_2_detect(Scsi_Host_Template *tpnt)
                info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH;
                info->info.ifcfg.cntl3          = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
                info->info.ifcfg.disconnect_ok  = 1;
+               info->info.ifcfg.wide_max_size  = 0;
                info->info.dma.setup            = cumanascsi_2_dma_setup;
                info->info.dma.pseudo           = cumanascsi_2_dma_pseudo;
                info->info.dma.stop             = cumanascsi_2_dma_stop;
index 301b83d05af35c6db5571a617a87b9c0718d496a..8ed77e15791145e941f2652e4a5b854637197bf9 100644 (file)
@@ -38,9 +38,6 @@
 #include "../../scsi/hosts.h"
 #include "eesox.h"
 
-#define NO_IRQ 255
-#define NO_DMA 255
-
 /* Configuration */
 #define EESOX_XTALFREQ         40
 #define EESOX_ASYNC_PERIOD     200
@@ -123,6 +120,8 @@ static const expansioncard_ops_t eesoxscsi_ops = {
        eesoxscsi_irqenable,
        eesoxscsi_irqdisable,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
@@ -379,6 +378,7 @@ eesoxscsi_detect(Scsi_Host_Template *tpnt)
                info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH;
                info->info.ifcfg.cntl3          = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
                info->info.ifcfg.disconnect_ok  = 1;
+               info->info.ifcfg.wide_max_size  = 0;
                info->info.dma.setup            = eesoxscsi_dma_setup;
                info->info.dma.pseudo           = eesoxscsi_dma_pseudo;
                info->info.dma.stop             = eesoxscsi_dma_stop;
index 6cd638242847ae18179cdc76e8fa6a67f462f899..c89b74f1e53284553173fedd11d024323884348f 100644 (file)
@@ -24,9 +24,9 @@
  *  02-05-1998 RMK     Added extra checks in fas216_reset
  *  24-05-1998 RMK     Fixed synchronous transfers with period >= 200ns
  *  27-06-1998 RMK     Changed asm/delay.h to linux/delay.h
+ *  26-08-1998 RMK     Improved message support wrt MESSAGE_REJECT
  *
  * Todo:
- *  - tighten up the MESSAGE_REJECT support.
  *  - allow individual devices to enable sync xfers.
  */
 
@@ -57,7 +57,7 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
 
 #define VER_MAJOR      0
 #define VER_MINOR      0
-#define VER_PATCH      4
+#define VER_PATCH      5
 
 #define SCSI2_TAG
 
@@ -86,6 +86,8 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
  */
 #define SCSI2_SYNC
 
+#define SCSI2_WIDE
+
 #undef DEBUG_CONNECT
 #undef DEBUG_BUSSERVICE
 #undef DEBUG_FUNCTIONDONE
@@ -132,8 +134,8 @@ static void fas216_dumpinfo(FAS216_Info *info)
        printk("           SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n",
                info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
                info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual);
-       printk("      msgs async_stp=%X last_message=%X disconnectable=%d aborting=%d }\n",
-               info->scsi.async_stp, info->scsi.last_message,
+       printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",
+               info->scsi.async_stp,
                info->scsi.disconnectable, info->scsi.aborting);
        printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
               "            disconnects=%X aborts=%X resets=%X }\n",
@@ -144,10 +146,10 @@ static void fas216_dumpinfo(FAS216_Info *info)
                info->ifcfg.clockrate, info->ifcfg.select_timeout,
                info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
        for (i = 0; i < 8; i++) {
-               printk("    busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X negstate=%X }\n",
+               printk("    busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
                        i, info->busyluns[i], i,
                        info->device[i].disconnect_ok, info->device[i].stp,
-                       info->device[i].sof, info->device[i].negstate);
+                       info->device[i].sof, info->device[i].sync_state);
        }
        printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
                info->dma.transfer_type, info->dma.setup,
@@ -192,19 +194,19 @@ static const char *fas216_bus_phase(int stat)
 static const char *fas216_drv_phase(FAS216_Info *info)
 {
        switch (info->scsi.phase) {
-       case PHASE_IDLE:        return "idle";
-       case PHASE_SELECTION:   return "selection";
-       case PHASE_MESSAGESENT: return "message sent";
-       case PHASE_RECONNECTED: return "reconnected";
-       case PHASE_DATAOUT:     return "data out";
-       case PHASE_DATAIN:      return "data in";
-       case PHASE_MSGOUT:      return "message out";
-       case PHASE_MSGIN:       return "message in";
-       case PHASE_AFTERMSGOUT: return "after message out";
-       case PHASE_STATUS:      return "status";
-       case PHASE_DISCONNECT:  return "disconnect";
-       case PHASE_DONE:        return "done";
-       default:                return "???";
+       case PHASE_IDLE:                return "idle";
+       case PHASE_SELECTION:           return "selection";
+       case PHASE_COMMAND:             return "command";
+       case PHASE_RECONNECTED:         return "reconnected";
+       case PHASE_DATAOUT:             return "data out";
+       case PHASE_DATAIN:              return "data in";
+       case PHASE_MSGIN:               return "message in";
+       case PHASE_MSGIN_DISCONNECT:    return "disconnect";
+       case PHASE_MSGOUT_EXPECT:       return "expect message out";
+       case PHASE_MSGOUT:              return "message out";
+       case PHASE_STATUS:              return "status";
+       case PHASE_DONE:                return "done";
+       default:                        return "???";
        }
 }
 
@@ -262,6 +264,37 @@ static int fas216_clockrate(int clock)
        return clock;
 }
 
+/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos)
+ * Purpose : retrieve a last message from the list, using position in fifo
+ * Params  : info - interface to search
+ *         : pos  - current fifo position
+ */
+static inline unsigned short
+fas216_get_last_msg(FAS216_Info *info, int pos)
+{
+       unsigned short packed_msg = NOP;
+       struct message *msg;
+       int msgnr = 0;
+
+       while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+               if (pos >= msg->fifo)
+                       break;
+       }
+
+       if (msg) {
+               if (msg->msg[0] == EXTENDED_MESSAGE)
+                       packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
+               else
+                       packed_msg = msg->msg[0];
+       }
+
+#ifdef DEBUG_MESSAGES
+       printk("Message: %04X found at position %02X\n",
+               packed_msg, pos);
+#endif
+       return packed_msg;
+}
+
 /* Function: int fas216_syncperiod(FAS216_Info *info, int ns)
  * Purpose : Calculate value to be loaded into the STP register
  *           for a given period in ns
@@ -303,6 +336,240 @@ fas216_set_sync(FAS216_Info *info, int target)
                outb(info->scsi.cfg[2], REG_CNTL3(info));
 }
 
+/* Synchronous transfer support
+ *
+ * Note: The SCSI II r10 spec says (5.6.12):
+ *
+ *  (2)  Due to historical problems with early host adapters that could
+ *  not accept an SDTR message, some targets may not initiate synchronous
+ *  negotiation after a power cycle as required by this standard.  Host
+ *  adapters that support synchronous mode may avoid the ensuing failure
+ *  modes when the target is independently power cycled by initiating a
+ *  synchronous negotiation on each REQUEST SENSE and INQUIRY command.
+ *  This approach increases the SCSI bus overhead and is not recommended
+ *  for new implementations.  The correct method is to respond to an
+ *  SDTR message with a MESSAGE REJECT message if the either the
+ *  initiator or target devices does not support synchronous transfers
+ *  or does not want to negotiate for synchronous transfers at the time.
+ *  Using the correct method assures compatibility with wide data
+ *  transfers and future enhancements.
+ *
+ * We will always initiate a synchronous transfer negociation request on
+ * every INQUIRY or REQUEST SENSE message, unless the target itself has
+ * at some point performed a synchronous transfer negociation request, or
+ * we have synchronous transfers disabled for this device.
+ */
+
+/* Function: void fas216_handlesync(FAS216_Info *info, char *msg)
+ * Purpose : Handle a synchronous transfer message from the target
+ * Params  : info - state structure for interface
+ *         : msg  - message from target
+ */
+static void
+fas216_handlesync(FAS216_Info *info, char *msg)
+{
+       struct fas216_device *dev = &info->device[info->SCpnt->target];
+       enum { sync, async, none, reject } res = none;
+
+#ifdef SCSI2_SYNC
+       switch (msg[0]) {
+       case MESSAGE_REJECT:
+               /* Synchronous transfer request failed.
+                * Note: SCSI II r10:
+                *
+                *  SCSI devices that are capable of synchronous
+                *  data transfers shall not respond to an SDTR
+                *  message with a MESSAGE REJECT message.
+                *
+                * Hence, if we get this condition, we disable
+                * negociation for this device.
+                */
+               if (dev->sync_state == neg_inprogress) {
+                       dev->sync_state = neg_invalid;
+                       res = async;
+               }
+               break;
+
+       case EXTENDED_MESSAGE:
+               switch (dev->sync_state) {
+               /* We don't accept synchronous transfer requests.
+                * Respond with a MESSAGE_REJECT to prevent a
+                * synchronous transfer agreement from being reached.
+                */
+               case neg_invalid:
+                       res = reject;
+                       break;
+
+               /* We were not negociating a synchronous transfer,
+                * but the device sent us a negociation request.
+                * Honour the request by sending back a SDTR
+                * message containing our capability, limited by
+                * the targets capability.
+                */
+               default:
+                       outb(CMD_SETATN, REG_CMD(info));
+                       if (msg[4] > info->ifcfg.sync_max_depth)
+                               msg[4] = info->ifcfg.sync_max_depth;
+                       if (msg[3] < 1000 / info->ifcfg.clockrate)
+                               msg[3] = 1000 / info->ifcfg.clockrate;
+
+                       msgqueue_flush(&info->scsi.msgs);
+                       msgqueue_addmsg(&info->scsi.msgs, 5,
+                                       EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+                                       msg[3], msg[4]);
+                       info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+                       /* This is wrong.  The agreement is not in effect
+                        * until this message is accepted by the device
+                        */
+                       dev->sync_state = neg_targcomplete;
+                       res = sync;
+                       break;
+
+               /* We initiated the synchronous transfer negociation,
+                * and have successfully received a response from the
+                * target.  The synchronous transfer agreement has been
+                * reached.  Note: if the values returned are out of our
+                * bounds, we must reject the message.
+                */
+               case neg_inprogress:
+                       res = reject;
+                       if (msg[4] <= info->ifcfg.sync_max_depth &&
+                           msg[3] >= 1000 / info->ifcfg.clockrate) {
+                               dev->sync_state = neg_complete;
+                               res = sync;
+                       }
+                       break;
+               }
+       }
+#else
+       res = reject;
+#endif
+
+       switch (res) {
+       case sync:
+               dev->period = msg[3];
+               dev->sof    = msg[4];
+               dev->stp    = fas216_syncperiod(info, msg[3] * 4);
+               fas216_set_sync(info, info->SCpnt->target);
+               break;
+
+       case reject:
+               outb(CMD_SETATN, REG_CMD(info));
+               msgqueue_flush(&info->scsi.msgs);
+               msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+       case async:
+               dev->period = info->ifcfg.asyncperiod / 4;
+               dev->sof    = 0;
+               dev->stp    = info->scsi.async_stp;
+               fas216_set_sync(info, info->SCpnt->target);
+               break;
+
+       case none:
+               break;
+       }
+}
+
+/* Function: void fas216_handlewide(FAS216_Info *info, char *msg)
+ * Purpose : Handle a wide transfer message from the target
+ * Params  : info - state structure for interface
+ *         : msg  - message from target
+ */
+static void
+fas216_handlewide(FAS216_Info *info, char *msg)
+{
+       struct fas216_device *dev = &info->device[info->SCpnt->target];
+       enum { wide, bit8, none, reject } res = none;
+
+#ifdef SCSI2_WIDE
+       switch (msg[0]) {
+       case MESSAGE_REJECT:
+               /* Wide transfer request failed.
+                * Note: SCSI II r10:
+                *
+                *  SCSI devices that are capable of wide
+                *  data transfers shall not respond to a
+                *  WDTR message with a MESSAGE REJECT message.
+                *
+                * Hence, if we get this condition, we never
+                * reattempt negociation for this device.
+                */
+               if (dev->wide_state == neg_inprogress) {
+                       dev->wide_state = neg_invalid;
+                       res = bit8;
+               }
+               break;
+
+       case EXTENDED_MESSAGE:
+               switch (dev->wide_state) {
+               /* We don't accept wide data transfer requests.
+                * Respond with a MESSAGE REJECT to prevent a
+                * wide data transfer agreement from being reached.
+                */
+               case neg_invalid:
+                       res = reject;
+                       break;
+
+               /* We were not negociating a wide data transfer,
+                * but the device sent is a negociation request.
+                * Honour the request by sending back a WDTR
+                * message containing our capability, limited by
+                * the targets capability.
+                */
+               default:
+                       outb(CMD_SETATN, REG_CMD(info));
+                       if (msg[3] > info->ifcfg.wide_max_size)
+                               msg[3] = info->ifcfg.wide_max_size;
+
+                       msgqueue_flush(&info->scsi.msgs);
+                       msgqueue_addmsg(&info->scsi.msgs, 4,
+                                       EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+                                       msg[3]);
+                       info->scsi.phase = PHASE_MSGOUT_EXPECT;
+                       res = wide;
+                       break;
+
+               /* We initiated the wide data transfer negociation,
+                * and have successfully received a response from the
+                * target.  The synchronous transfer agreement has been
+                * reached.  Note: if the values returned are out of our
+                * bounds, we must reject the message.
+                */
+               case neg_inprogress:
+                       res = reject;
+                       if (msg[3] <= info->ifcfg.wide_max_size) {
+                               dev->wide_state = neg_complete;
+                               res = wide;
+                       }
+                       break;
+               }
+       }
+#else
+       res = reject;
+#endif
+
+       switch (res) {
+       case wide:
+               dev->wide_xfer = msg[3];
+               break;
+
+       case reject:
+               outb(CMD_SETATN, REG_CMD(info));
+               msgqueue_flush(&info->scsi.msgs);
+               msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+       case bit8:
+               dev->wide_xfer = 0;
+               break;
+
+       case none:
+               break;
+       }
+}
+
 /* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
  * Purpose : update data pointers after transfer suspended/paused
  * Params  : info              - interface's local pointer to update
@@ -338,6 +605,9 @@ fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
        residual -= bytes_transferred;
        ptr += bytes_transferred;
 
+       if (residual == 0)
+               ptr = NULL;
+
        info->scsi.SCp.ptr = ptr;
        info->scsi.SCp.this_residual = residual;
 }
@@ -353,7 +623,7 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
 {
        unsigned int residual;
        char *ptr;
-       int correction;
+       int correction = 0;
 
        fas216_checkmagic(info, "fas216_pio");
 
@@ -361,23 +631,24 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
        ptr = info->scsi.SCp.ptr;
 
        if (direction == DMA_OUT) {
-               while (residual > 0) {
-                       if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
+//             while (residual > 0) {
+//                     if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
                                outb(*ptr++, REG_FF(info));
                                residual -= 1;
-                       } else if (inb(REG_STAT(info)) & STAT_INT)
-                               break;
-               }
-               correction = inb(REG_CFIS(info)) & CFIS_CF;
+//                     }
+//                     if (inb(REG_STAT(info)) & STAT_INT)
+//                             break;
+//             }
+//             correction = inb(REG_CFIS(info)) & CFIS_CF;
        } else {
-               while (residual > 0) {
-                       if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
+//             while (residual > 0) {
+//                     if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
                                *ptr++ = inb(REG_FF(info));
                                residual -= 1;
-                       } else if (inb(REG_STAT(info)) & STAT_INT)
-                               break;
-               }
-               correction = 0;
+//                     }
+//                     if (inb(REG_STAT(info)) & STAT_INT)
+//                             break;
+//             }
        }
 
        ptr -= correction;
@@ -549,10 +820,11 @@ fas216_disconnect_intr(FAS216_Info *info)
 
        switch (info->scsi.phase) {
        case PHASE_SELECTION:                   /* while selecting - no target          */
+       case PHASE_SELSTEPS:
                fas216_done(info, DID_NO_CONNECT);
                break;
 
-       case PHASE_DISCONNECT:                  /* message in - disconnecting           */
+       case PHASE_MSGIN_DISCONNECT:            /* message in - disconnecting           */
                outb(CMD_ENABLESEL, REG_CMD(info));
                info->scsi.disconnectable = 1;
                info->scsi.reconnected.tag = 0;
@@ -564,8 +836,8 @@ fas216_disconnect_intr(FAS216_Info *info)
                fas216_done(info, DID_OK);
                break;
 
-       case PHASE_AFTERMSGOUT:                 /* message out - possible ABORT message */
-               if (info->scsi.last_message == ABORT) {
+       case PHASE_MSGOUT:                      /* message out - possible ABORT message */
+               if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
                        info->scsi.aborting = 0;
                        fas216_done(info, DID_ABORT);
                        break;
@@ -592,14 +864,17 @@ fas216_reselected_intr(FAS216_Info *info)
 
        fas216_checkmagic(info, "fas216_reselected_intr");
 
-       if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) {
+       if ((info->scsi.phase == PHASE_SELECTION ||
+            info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
                Scsi_Cmnd *SCpnt = info->SCpnt;
 
                info->origSCpnt = SCpnt;
                info->SCpnt = NULL;
 
-               if (info->device[SCpnt->target].negstate == syncneg_sent)
-                       info->device[SCpnt->target].negstate = syncneg_start;
+               if (info->device[SCpnt->target].wide_state == neg_inprogress)
+                       info->device[SCpnt->target].wide_state = neg_wait;
+               if (info->device[SCpnt->target].sync_state == neg_inprogress)
+                       info->device[SCpnt->target].sync_state = neg_wait;
        }
 
 #ifdef DEBUG_CONNECT
@@ -607,15 +882,14 @@ fas216_reselected_intr(FAS216_Info *info)
                fas216_target(info), info->scsi.phase);
 #endif
 
-       msgqueue_flush(&info->scsi.msgs);
-
        if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) {
                printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
                        info->host->host_no);
                outb(CMD_SETATN, REG_CMD(info));
-               msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-               info->scsi.phase = PHASE_MSGOUT;
                outb(CMD_MSGACCEPTED, REG_CMD(info));
+               msgqueue_flush(&info->scsi.msgs);
+               msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
                return;
        }
 
@@ -636,13 +910,14 @@ fas216_reselected_intr(FAS216_Info *info)
 
        if (!ok) {
                /*
-                * Something went wrong - abort the command on
-                * the target.  Should this be INITIATOR_ERROR ?
+                * Something went wrong - send an initiator error to
+                * the target.
                 */
                outb(CMD_SETATN, REG_CMD(info));
-               msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
-               info->scsi.phase = PHASE_MSGOUT;
                outb(CMD_MSGACCEPTED, REG_CMD(info));
+               msgqueue_flush(&info->scsi.msgs);
+               msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
                return;
        }
 
@@ -672,17 +947,20 @@ fas216_reselected_intr(FAS216_Info *info)
        if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg))
                ok = 1;
 
+       msgqueue_flush(&info->scsi.msgs);
        if (ok) {
                info->scsi.phase = PHASE_RECONNECTED;
                outb(target, REG_SDID(info));
        } else {
                /*
-                * Our command structure not found - abort the command on the target
-                * Should this be INITIATOR_ERROR ?
+                * Our command structure not found - abort the
+                * command on the target.  Since we have no
+                * record of this command, we can't send
+                * an INITIATOR DETECTED ERROR message.
                 */
                outb(CMD_SETATN, REG_CMD(info));
                msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
-               info->scsi.phase = PHASE_MSGOUT;
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
        }
        outb(CMD_MSGACCEPTED, REG_CMD(info));
 }
@@ -733,8 +1011,14 @@ fas216_finish_reconnect(FAS216_Info *info)
        }
        if (!info->SCpnt) {
                outb(CMD_SETATN, REG_CMD(info));
-               msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
-               info->scsi.phase = PHASE_MSGOUT;
+               msgqueue_flush(&info->scsi.msgs);
+#if 0
+               if (info->scsi.reconnected.tag)
+                       msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag);
+               else
+#endif
+                       msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
+               info->scsi.phase = PHASE_MSGOUT_EXPECT;
                info->scsi.aborting = 1;
        } else {
                /*
@@ -751,6 +1035,28 @@ fas216_finish_reconnect(FAS216_Info *info)
 #endif
 }
 
+static unsigned char fas216_get_msg_byte(FAS216_Info *info)
+{
+       int tout;
+
+       outb(CMD_MSGACCEPTED, REG_CMD(info));
+       for (tout = 1000000; tout; tout --)
+               if (inb(REG_STAT(info)) & STAT_INT)
+                       break;
+
+       inb(REG_INST(info));
+
+       outb(CMD_TRANSFERINFO, REG_CMD(info));
+
+       for (tout = 1000000; tout; tout --)
+               if (inb(REG_STAT(info)) & STAT_INT)
+                       break;
+
+       inb(REG_INST(info));
+
+       return inb(REG_FF(info));
+}
+
 /* Function: void fas216_message(FAS216_Info *info)
  * Purpose : handle a function done interrupt from FAS216 chip
  * Params  : info - interface which caused function done interrupt
@@ -765,34 +1071,10 @@ static void fas216_message(FAS216_Info *info)
        message[0] = inb(REG_FF(info));
 
        if (message[0] == EXTENDED_MESSAGE) {
-               int tout;
-               outb(CMD_MSGACCEPTED, REG_CMD(info));
-               for (tout = 1000000; tout; tout--)
-                       if (inb(REG_STAT(info)) & STAT_INT)
-                               break;
-               inb(REG_INST(info));
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               for (tout = 1000000; tout; tout--)
-                       if (inb(REG_STAT(info)) & STAT_INT)
-                               break;
-               inb(REG_INST(info));
-
-               message[1] = inb(REG_FF(info));
+               message[1] = fas216_get_msg_byte(info);
 
-               for (msglen = 2; msglen < message[1] + 2; msglen++) {
-                       outb(CMD_MSGACCEPTED, REG_CMD(info));
-                       for (tout = 1000000; tout; tout--)
-                               if (inb(REG_STAT(info)) & STAT_INT)
-                                       break;
-                       inb(REG_INST(info));
-                       outb(CMD_TRANSFERINFO, REG_CMD(info));
-                       for (tout = 1000000; tout; tout--)
-                               if (inb(REG_STAT(info)) & STAT_INT)
-                                       break;
-                       inb(REG_INST(info));
-
-                       message[msglen] = inb(REG_FF(info));
-               }
+               for (msglen = 2; msglen < message[1] + 2; msglen++)
+                       message[msglen] = fas216_get_msg_byte(info);
        }
 
 #ifdef DEBUG_MESSAGES
@@ -806,6 +1088,7 @@ static void fas216_message(FAS216_Info *info)
                printk("\n");
        }
 #endif
+
        if (info->scsi.phase == PHASE_RECONNECTED) {
                if (message[0] == SIMPLE_QUEUE_TAG)
                        info->scsi.reconnected.tag = message[1];
@@ -815,14 +1098,22 @@ static void fas216_message(FAS216_Info *info)
 
        switch (message[0]) {
        case COMMAND_COMPLETE:
-               printk("fas216: command complete with no status in MESSAGE_IN?\n");
+               printk(KERN_ERR "scsi%d.%c: command complete with no "
+                       "status in MESSAGE_IN?\n",
+                       info->host->host_no, fas216_target(info));
                break;
 
        case SAVE_POINTERS:
                /*
                 * Save current data pointer to SAVED data pointer
+                * SCSI II standard says that we must not acknowledge
+                * this until we have really saved pointers.
+                * NOTE: we DO NOT save the command nor status pointers
+                * as required by the SCSI II standard.  These always
+                * point to the start of their respective areas.
                 */
                info->SCpnt->SCp = info->scsi.SCp;
+               info->SCpnt->SCp.sent_command = 0;
 #if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT)
                printk("scsi%d.%c: save data pointers: [%p, %X]\n",
                        info->host->host_no, fas216_target(info),
@@ -843,13 +1134,27 @@ static void fas216_message(FAS216_Info *info)
                break;
 
        case DISCONNECT:
-               info->scsi.phase = PHASE_DISCONNECT;
+               info->scsi.phase = PHASE_MSGIN_DISCONNECT;
                break;
 
        case MESSAGE_REJECT:
-               printk("scsi%d.%c: reject, last message %04X\n",
-                       info->host->host_no, fas216_target(info),
-                       info->scsi.last_message);
+               switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
+               case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
+                       fas216_handlesync(info, message);
+                       break;
+
+               case EXTENDED_MESSAGE | EXTENDED_WDTR << 8:
+                       fas216_handlewide(info, message);
+                       break;
+
+               default:
+                       printk("scsi%d.%c: reject, last message %04X\n",
+                               info->host->host_no, fas216_target(info),
+                               fas216_get_last_msg(info, info->scsi.msgin_fifo));
+               }
+               break;
+
+       case NOP:
                break;
 
        case SIMPLE_QUEUE_TAG:
@@ -862,49 +1167,18 @@ static void fas216_message(FAS216_Info *info)
        case EXTENDED_MESSAGE:
                switch (message[2]) {
                case EXTENDED_SDTR:     /* Sync transfer negociation request/reply */
-                       switch (info->device[info->SCpnt->target].negstate) {
-                       case syncneg_invalid:
-                               msgqueue_flush(&info->scsi.msgs);
-                               outb(CMD_SETATN, REG_CMD(info));
-                               msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-                               info->scsi.phase = PHASE_MSGOUT;
-                               break;
-
-                       default:
-                               if (message[4] > info->ifcfg.sync_max_depth)
-                                       message[4] = info->ifcfg.sync_max_depth;
-                               if (message[3] < 1000 / info->ifcfg.clockrate)
-                                       message[3] = 1000 / info->ifcfg.clockrate;
-
-                               outb(CMD_SETATN, REG_CMD(info));
-                               msgqueue_addmsg(&info->scsi.msgs, 5,
-                                               EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
-                                               message[3], message[4]);
-                               info->scsi.phase = PHASE_MSGOUT;
-                       case syncneg_sent:
-                               info->device[info->SCpnt->target].negstate = syncneg_complete;
-                               info->device[info->SCpnt->target].period = message[3];
-                               info->device[info->SCpnt->target].sof = message[4];
-                               info->device[info->SCpnt->target].stp =
-                                       fas216_syncperiod(info, message[3] * 4);
-                               printk(KERN_NOTICE "scsi%d.%c: using synchronous transfer, offset %d, %d ns\n",
-                                       info->host->host_no, fas216_target(info), message[4], message[3] * 4);
-                               fas216_set_sync(info, info->SCpnt->target);
-                               break;
-                       }
+                       fas216_handlesync(info, message);
                        break;
 
                case EXTENDED_WDTR:     /* Wide transfer negociation request/reply */
-                       /* We don't do wide transfers - reject message */
+                       fas216_handlewide(info, message);
+                       break;
+
                default:
                        printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n",
                                info->host->host_no, fas216_target(info),
                                message[2]);
-                       msgqueue_flush(&info->scsi.msgs);
-                       outb(CMD_SETATN, REG_CMD(info));
-                       msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-                       info->scsi.phase = PHASE_MSGOUT;
-                       break;
+                       goto reject_message;
                }
                break;
 
@@ -912,13 +1186,17 @@ static void fas216_message(FAS216_Info *info)
                printk("scsi%d.%c: unrecognised message %02X, rejecting\n",
                        info->host->host_no, fas216_target(info),
                        message[0]);
-               msgqueue_flush(&info->scsi.msgs);
-               outb(CMD_SETATN, REG_CMD(info));
-               msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-               info->scsi.phase = PHASE_MSGOUT;
-               break;
+               goto reject_message;
        }
        outb(CMD_MSGACCEPTED, REG_CMD(info));
+       return;
+
+reject_message:
+       outb(CMD_SETATN, REG_CMD(info));
+       outb(CMD_MSGACCEPTED, REG_CMD(info));
+       msgqueue_flush(&info->scsi.msgs);
+       msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+       info->scsi.phase = PHASE_MSGOUT_EXPECT;
 }
 
 /* Function: void fas216_send_command(FAS216_Info *info)
@@ -935,201 +1213,46 @@ static void fas216_send_command(FAS216_Info *info)
        outb(CMD_FLUSHFIFO, REG_CMD(info));
 
        /* load command */
-       for (i = 0; i < info->SCpnt->cmd_len; i++)
+       for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
                outb(info->SCpnt->cmnd[i], REG_FF(info));
 
        outb(CMD_TRANSFERINFO, REG_CMD(info));
-}
-
-/* Function: int fas216_busservice_selection(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in selection phase
- * Params  : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- */
-static int fas216_busservice_selection(FAS216_Info *info, unsigned int stat)
-{
-       fas216_checkmagic(info, "fas216_busservice_selection");
-
-       switch (stat & STAT_BUSMASK) {
-       case STAT_DATAOUT:      /* data out phase                       */
-               fas216_starttransfer(info, DMA_OUT, 1);
-               return 1;
-
-       case STAT_DATAIN:               /* data in phase                */
-               fas216_starttransfer(info, DMA_IN, 0);
-               return 1;
-
-       case STAT_STATUS:               /* status phase                 */
-               info->scsi.phase = PHASE_STATUS;
-               outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
-               return 1;
-
-       case STAT_MESGIN:               /* message in phase             */
-               info->scsi.phase = PHASE_MSGIN;
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               return 1;
-
-       case STAT_MESGOUT:{             /* message out phase            */
-               char *msg;
-               int start = 1, msglen;
-
-               /* load message bytes, but don't forget to miss the first
-                * byte!
-                */
-               while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
-                       int i;
-
-                       for (i = start; i < msglen; i++)
-                               outb(msg[i], REG_FF(info));
-                       start = 0;
-               }
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               info->scsi.phase = PHASE_MESSAGESENT;
-               return 1;
-       }
-       default:
-               return 0;
-       }
-}
-
-/* Function: int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service after the IDENTIFY message has been sent
- * Params  : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- */
-static int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat)
-{
-       fas216_checkmagic(info, "fas216_busservice_messagesent");
-
-       switch (stat & STAT_BUSMASK) {
-       case STAT_MESGIN:               /* message in phase             */
-               info->scsi.phase = PHASE_MSGIN;
-               outb(CMD_FLUSHFIFO, REG_CMD(info));
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               return 1;
 
-       case STAT_COMMAND:              /* command phase                */
-               fas216_send_command(info);
-               return 1;
-
-       default:
-               return 0;
-       }
+       info->scsi.phase = PHASE_COMMAND;
 }
 
-/* Function: int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in a data in/out phase.
- * Params  : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- * Note    : We do not allow the device to change the data direction!
- */
-static int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat)
-{
-       fas216_checkmagic(info, "fas216_busservice_dataphase");
-
-       switch (stat & STAT_BUSMASK) {
-       case STAT_DATAIN:               /* continue data in phase       */
-               if (info->scsi.phase == PHASE_DATAIN) {
-                       fas216_starttransfer(info, DMA_IN, 0);
-                       return 1;
-               } else
-                       return 0;
-
-       case STAT_DATAOUT:              /* continue data out phase      */
-               if (info->scsi.phase == PHASE_DATAOUT) {
-                       fas216_starttransfer(info, DMA_OUT, 0);
-                       return 1;
-               } else
-                       return 0;
-
-       case STAT_STATUS:               /* status in phase              */
-               fas216_stoptransfer(info);
-               info->scsi.phase = PHASE_STATUS;
-               outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
-               return 1;
-
-       case STAT_MESGIN:               /* message in phase             */
-               fas216_stoptransfer(info);
-               info->scsi.phase = PHASE_MSGIN;
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               return 1;
-
-       default:
-               return 0;
-       }
-}
-
-/* Function: int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in after a reconnection
+/* Function: void fas216_send_messageout(FAS216_Info *info, int start)
+ * Purpose : handle bus service to send a message
  * Params  : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
  * Note    : We do not allow the device to change the data direction!
  */
-static int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat)
+static void fas216_send_messageout(FAS216_Info *info, int start)
 {
-       fas216_checkmagic(info, "fas216_busservice_reconnected");
-
-       switch (stat & STAT_BUSMASK) {
-       case STAT_MESGIN:
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               return 1;
-
-       case STAT_STATUS:
-               fas216_finish_reconnect(info);
-               info->scsi.phase = PHASE_STATUS;
-               outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
-               return 1;
-
-       case STAT_DATAOUT:              /* data out phase               */
-               fas216_finish_reconnect(info);
-               fas216_starttransfer(info, DMA_OUT, 1);
-               return 1;
+       unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
 
-       case STAT_DATAIN:               /* data in phase                */
-               fas216_finish_reconnect(info);
-               fas216_starttransfer(info, DMA_IN, 0);
-               return 1;
+       fas216_checkmagic(info, "fas216_send_messageout");
 
-       default:
-               return 0;
-       }
-}
+       outb(CMD_FLUSHFIFO, REG_CMD(info));
 
-/* Function: int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service to send a message
- * Params  : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- * Note    : We do not allow the device to change the data direction!
- */
-static int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat)
-{
-       fas216_checkmagic(info, "fas216_busservice_messageout");
+       if (tot_msglen) {
+               struct message *msg;
+               int msgnr = 0;
 
-       if ((stat & STAT_BUSMASK) != STAT_MESGOUT) {
-               printk("scsi%d.%c: didn't manage MESSAGE OUT phase\n",
-                      info->host->host_no, fas216_target(info));
-               return 0;
-       } else {
-               unsigned int msglen = msgqueue_msglength(&info->scsi.msgs);
+               while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+                       int i;
 
-               outb(CMD_FLUSHFIFO, REG_CMD(info));
+                       for (i = start; i < msg->length; i++)
+                               outb(msg->msg[i], REG_FF(info));
 
-               if (msglen == 0)
-                       outb(NOP, REG_FF(info));
-               else {
-                       char *msg;
+                       msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
+                       start = 0;
+               }
+       } else
+               outb(NOP, REG_FF(info));
 
-                       while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
-                               int i;
+       outb(CMD_TRANSFERINFO, REG_CMD(info));
 
-                               for (i = 0; i < msglen; i++)
-                                       outb(msg[i], REG_FF(info));
-                       }
-               }
-               outb(CMD_TRANSFERINFO, REG_CMD(info));
-               info->scsi.phase = PHASE_AFTERMSGOUT;
-               return 1;
-       }
+       info->scsi.phase = PHASE_MSGOUT;
 }
 
 /* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
@@ -1151,91 +1274,150 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
        case IS_COMPLETE:                       /* last action completed                */
                outb(CMD_NOP, REG_CMD(info));
 
-               switch (info->scsi.phase) {
-               case PHASE_SELECTION:           /* while selecting - selected target    */
-                       if (!fas216_busservice_selection(info, stat))
-                               printk("scsi%d.%c: bus phase %s after connect?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat));
-                       break;
-
-               case PHASE_MESSAGESENT:
-                       if (!fas216_busservice_messagesent(info, stat))
-                               printk("scsi%d.%c: bus phase %s after message sent?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat));
-                       break;
+#define STATE(st,ph) ((ph) << 3 | (st))
+               /* This table describes the legal SCSI state transitions,
+                * as described by the SCSI II spec.
+                */
+               switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
+                                                       /* Reselmsgin   -> Data In      */
+               case STATE(STAT_DATAIN, PHASE_RECONNECTED):
+                       fas216_finish_reconnect(info);
+               case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
+               case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
+               case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
+               case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
+               case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
+                       fas216_starttransfer(info, DMA_IN, 0);
+                       return;
 
-               case PHASE_DATAIN:              /* while transfering data in            */
-               case PHASE_DATAOUT:             /* while transfering data out           */
-                       if (!fas216_busservice_dataphase(info, stat))
-                               printk("scsi%d.%c: bus phase %s after %s?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat), fas216_drv_phase(info));
-                       break;
+               case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
+                       fas216_starttransfer(info, DMA_OUT, 0);
+                       return;
+
+                                                       /* Reselmsgin   -> Data Out     */
+               case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
+                       fas216_finish_reconnect(info);
+               case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
+               case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
+               case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
+               case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
+                       fas216_starttransfer(info, DMA_OUT, 1);
+                       return;
+
+                                                       /* Reselmsgin   -> Status       */
+               case STATE(STAT_STATUS, PHASE_RECONNECTED):
+                       fas216_finish_reconnect(info);
+                       goto status;
+               case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
+               case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
+                       fas216_stoptransfer(info);
+               case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
+               case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
+               case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
+               case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
+               status:
+                       outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
+                       info->scsi.phase = PHASE_STATUS;
+                       return;
+
+               case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
+               case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
+                       fas216_stoptransfer(info);
+               case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
+               case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
+                       info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+                       outb(CMD_TRANSFERINFO, REG_CMD(info));
+                       info->scsi.phase = PHASE_MSGIN;
+                       return;
 
-               case PHASE_RECONNECTED:         /* newly reconnected device             */
-                       /*
-                        * Command reconnected - if MESGIN, get message - it may be
-                        * the tag.  If not, get command out of the disconnected queue
+                                                       /* Reselmsgin   -> Message In   */
+               case STATE(STAT_MESGIN, PHASE_RECONNECTED):
+               case STATE(STAT_MESGIN, PHASE_MSGIN):
+                       info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+                       outb(CMD_TRANSFERINFO, REG_CMD(info));
+                       return;
+
+                                                       /* Reselmsgin   -> Command      */
+               case STATE(STAT_COMMAND, PHASE_RECONNECTED):
+                       fas216_finish_reconnect(info);
+               case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
+               case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
+                       fas216_send_command(info);
+                       info->scsi.phase = PHASE_COMMAND;
+                       return;
+                                                       /* Selection    -> Message Out  */
+               case STATE(STAT_MESGOUT, PHASE_SELECTION):
+                       fas216_send_messageout(info, 1);
+                       return;
+                                                       /* Any          -> Message Out  */
+               case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
+                       fas216_send_messageout(info, 0);
+                       return;
+
+               /* Error recovery rules.
+                *   These either attempt to abort or retry the operation.
+                * TODO: we need more of these
+                */
+               case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
+                       /* error - we've sent out all the command bytes
+                        * we have.
+                        * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
+                        * to include the command bytes sent for this to work
+                        * correctly.
                         */
-                       if (!fas216_busservice_reconnected(info, stat))
-                               printk("scsi%d.%c: bus phase %s after reconnect?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat));
-                       break;
-
-               case PHASE_MSGIN:
-               case PHASE_AFTERMSGOUT:
-                       switch (stat & STAT_BUSMASK) {
-                       case STAT_MESGIN:
-                               info->scsi.phase = PHASE_MSGIN;
-                               outb(CMD_TRANSFERINFO, REG_CMD(info));
-                               break;
-
-                       case STAT_COMMAND:      /* command phase                        */
-                               fas216_send_command(info);
-                               info->scsi.phase = PHASE_SELECTION;
-                               break;
-
-                       default:
-                               printk("scsi%d.%c: bus phase %s after %s?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat),
-                                       fas216_drv_phase(info));
-                       }
-                       break;
+                       printk(KERN_ERR "scsi%d.%c: "
+                               "target trying to receive more command bytes\n",
+                               info->host->host_no, fas216_target(info));
+                       outb(CMD_SETATN, REG_CMD(info));
+                       outb(15, REG_STCL(info));
+                       outb(0, REG_STCM(info));
+                       outb(0, REG_STCH(info));
+                       outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));
+                       msgqueue_flush(&info->scsi.msgs);
+                       msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+                       info->scsi.phase = PHASE_MSGOUT_EXPECT;
+                       return;
+
+                                                       /* Selection    -> Message Out  */
+               case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
+               case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out  -> Message Out  */
+                       /* If we get another message out phase, this
+                        * usually means some parity error occurred.
+                        * Resend complete set of messages.  If we have
+                        * more than 1 byte to send, we need to assert
+                        * ATN again.
+                        */
+                       if (msgqueue_msglength(&info->scsi.msgs) > 1)
+                               outb(CMD_SETATN, REG_CMD(info));
 
-               case PHASE_MSGOUT:
-                       if (!fas216_busservice_messageout(info, stat))
-                               printk("scsi%d.%c: bus phase %s instead of message out?\n",
-                                       info->host->host_no, fas216_target(info),
-                                       fas216_bus_phase(stat));
-                       break;
+                       fas216_send_messageout(info, 0);
+                       return;
+               }
 
-               case PHASE_DISCONNECT:
-                       printk("scsi%d.%c: disconnect message received, but bus service %s?\n",
+               if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
+                       printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
                                info->host->host_no, fas216_target(info),
                                fas216_bus_phase(stat));
+                       msgqueue_flush(&info->scsi.msgs);
                        outb(CMD_SETATN, REG_CMD(info));
                        msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-                       info->scsi.phase = PHASE_MSGOUT;
+                       info->scsi.phase = PHASE_MSGOUT_EXPECT;
                        info->scsi.aborting = 1;
                        outb(CMD_TRANSFERINFO, REG_CMD(info));
-                       break;
-
-               default:
-                       printk("scsi%d.%c: internal phase %s for bus service?"
-                               "  What do I do with this?\n",
-                               info->host->host_no, fas216_target(info),
-                               fas216_drv_phase(info));
+                       return;
                }
-               break;
+               printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
+                       info->host->host_no, fas216_target(info),
+                       fas216_bus_phase(stat),
+                       fas216_drv_phase(info));
+               print_debug_list();
+               return;
 
        default:
                printk("scsi%d.%c: bus service at step %d?\n",
                        info->host->host_no, fas216_target(info),
                        ssr & IS_BITS);
+               print_debug_list();
        }
 }
 
@@ -1269,6 +1451,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned
        case PHASE_MSGIN:                       /* message in phase                     */
        case PHASE_RECONNECTED:                 /* reconnected command                  */
                if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
+                       info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
                        fas216_message(info);
                        break;
                }
@@ -1300,10 +1483,11 @@ void fas216_intr(struct Scsi_Host *instance)
 
        if (stat & STAT_INT) {
                if (isr & INST_BUSRESET)
-                       printk("scsi%d.H: fas216: bus reset detected\n", instance->host_no);
-               else if (isr & INST_ILLEGALCMD)
+                       printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);
+               else if (isr & INST_ILLEGALCMD) {
                        printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
-               else if (isr & INST_DISCONNECT)
+                       fas216_dumpstate(info);
+               } else if (isr & INST_DISCONNECT)
                        fas216_disconnect_intr(info);
                else if (isr & INST_RESELECTED)         /* reselected                   */
                        fas216_reselected_intr(info);
@@ -1327,7 +1511,7 @@ void fas216_intr(struct Scsi_Host *instance)
 static void fas216_kick(FAS216_Info *info)
 {
        Scsi_Cmnd *SCpnt;
-       int i, msglen, from_queue = 0;
+       int tot_msglen, from_queue = 0;
 
        fas216_checkmagic(info, "fas216_kick");
 
@@ -1380,7 +1564,8 @@ static void fas216_kick(FAS216_Info *info)
 
        if (from_queue) {
 #ifdef SCSI2_TAG
-               if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
+               if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
+                   SCpnt->cmnd[0] != INQUIRY) {
                    SCpnt->device->current_tag += 1;
                        if (SCpnt->device->current_tag == 0)
                            SCpnt->device->current_tag = 1;
@@ -1409,6 +1594,7 @@ static void fas216_kick(FAS216_Info *info)
 
        /* build outgoing message bytes */
        msgqueue_flush(&info->scsi.msgs);
+
        if (info->device[SCpnt->target].disconnect_ok)
                msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
        else
@@ -1418,15 +1604,29 @@ static void fas216_kick(FAS216_Info *info)
        if (SCpnt->tag)
                msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
 
-       /* add synchronous negociation */
-       if (SCpnt->cmnd[0] == REQUEST_SENSE &&
-           info->device[SCpnt->target].negstate == syncneg_start) {
-               info->device[SCpnt->target].negstate = syncneg_sent;
+#ifdef SCSI2_WIDE
+       if (info->device[SCpnt->target].wide_state == neg_wait) {
+               info->device[SCpnt->target].wide_state = neg_inprogress;
+               msgqueue_addmsg(&info->scsi.msgs, 4,
+                               EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+                               info->ifcfg.wide_max_size);
+       }
+#ifdef SCSI2_SYNC
+       else
+#endif
+#endif
+#ifdef SCSI2_SYNC
+       if ((info->device[SCpnt->target].sync_state == neg_wait ||
+            info->device[SCpnt->target].sync_state == neg_complete) &&
+           (SCpnt->cmnd[0] == REQUEST_SENSE ||
+            SCpnt->cmnd[0] == INQUIRY)) {
+               info->device[SCpnt->target].sync_state = neg_inprogress;
                msgqueue_addmsg(&info->scsi.msgs, 5,
                                EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
                                1000 / info->ifcfg.clockrate,
                                info->ifcfg.sync_max_depth);
        }
+#endif
 
        /* following what the ESP driver says */
        outb(0, REG_STCL(info));
@@ -1444,25 +1644,29 @@ static void fas216_kick(FAS216_Info *info)
        /* synchronous transfers */
        fas216_set_sync(info, SCpnt->target);
 
-       msglen = msgqueue_msglength(&info->scsi.msgs);
+       tot_msglen = msgqueue_msglength(&info->scsi.msgs);
 
-       if (msglen == 1 || msglen == 3) {
+       if (tot_msglen == 1 || tot_msglen == 3) {
                /*
                 * We have an easy message length to send...
                 */
-               char *msg;
+               struct message *msg;
+               int msgnr = 0, i;
+
+               info->scsi.phase = PHASE_SELSTEPS;
 
                /* load message bytes */
-               while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
-                       for (i = 0; i < msglen; i++)
-                               outb(msg[i], REG_FF(info));
+               while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+                       for (i = 0; i < msg->length; i++)
+                               outb(msg->msg[i], REG_FF(info));
+                       msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
                }
 
                /* load command */
                for (i = 0; i < SCpnt->cmd_len; i++)
                        outb(SCpnt->cmnd[i], REG_FF(info));
 
-               if (msglen == 1)
+               if (tot_msglen == 1)
                        outb(CMD_SELECTATN, REG_CMD(info));
                else
                        outb(CMD_SELECTATN3, REG_CMD(info));
@@ -1471,17 +1675,11 @@ static void fas216_kick(FAS216_Info *info)
                 * We have an unusual number of message bytes to send.
                 *  Load first byte into fifo, and issue SELECT with ATN and
                 *  stop steps.
-                * Note: we only peek at t his message - we need the rest
-                * later on!
                 */
-               int thismsg;
-               char *msg = msgqueue_peeknextmsg(&info->scsi.msgs, &thismsg);
+               struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
 
-               if (!msg || thismsg < 1)
-                       printk(KERN_CRIT "scsi%d.%c: no message to send, but %d bytes\n",
-                               info->host->host_no, fas216_target(info), msglen);
-               else
-                       outb(msg[0], REG_FF(info));
+               outb(msg->msg[0], REG_FF(info));
+               msg->fifo = 1;
 
                outb(CMD_SELECTATNSTOP, REG_CMD(info));
        }
@@ -1525,11 +1723,15 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
                /*
                 * In theory, this should not happen, but just in case it does.
                 */
-               if (info->scsi.SCp.ptr && result == DID_OK) {
+               if (info->scsi.SCp.ptr &&
+                   info->scsi.SCp.this_residual &&
+                   result == DID_OK) {
                        switch (SCpnt->cmnd[0]) {
                        case INQUIRY:
                        case START_STOP:
                        case READ_CAPACITY:
+                       case TEST_UNIT_READY:
+                       case MODE_SENSE:
                                break;
 
                        default:
@@ -1579,6 +1781,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
 int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+       unsigned long flags;
 
        fas216_checkmagic(info, "fas216_queue_command");
 
@@ -1618,27 +1821,18 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        info->stats.queues += 1;
        SCpnt->tag = 0;
 
-       if (info->scsi.irq != NO_IRQ) {
-               unsigned long flags;
-
-               /* add command into execute queue and let it complete under
-                * the drivers interrupts.
-                */
-               if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
-                       SCpnt->result = DID_ERROR << 16;
-                       done(SCpnt);
-               }
-               save_flags_cli(flags);
-               if (!info->SCpnt || info->scsi.disconnectable)
-                       fas216_kick(info);
-               restore_flags(flags);
-       } else {
-               /* no interrupts to rely on - we'll have to handle the
-                * command ourselves.  For now, we give up.
-                */
+       /* add command into execute queue and let it complete under
+        * whatever scheme we're using.
+        */
+       if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
                SCpnt->result = DID_ERROR << 16;
                done(SCpnt);
        }
+       save_flags_cli(flags);
+       if (!info->SCpnt || info->scsi.disconnectable)
+               fas216_kick(info);
+       restore_flags(flags);
+
        return 0;
 }
 
@@ -1672,15 +1866,28 @@ int fas216_command(Scsi_Cmnd *SCpnt)
 
        /*
         * This wastes time, since we can't return until the command is
-        * complete. We can't seep either since we may get re-entered!
+        * complete. We can't sleep either since we may get re-entered!
         * However, we must re-enable interrupts, or else we'll be
         * waiting forever.
         */
        save_flags(flags);
        sti();
 
-       while (!info->internal_done)
-               barrier();
+       while (!info->internal_done) {
+               /*
+                * If we don't have an IRQ, then we must
+                * poll the card for it's interrupt, and
+                * use that to call this driver's interrupt
+                * routine.  That way, we keep the command
+                * progressing.
+                */
+               if (info->scsi.irq == NO_IRQ) {
+                       sti();
+                       while (!(inb(REG_STAT(info)) & STAT_INT));
+                       cli();
+                       fas216_intr(info->host);
+               }
+       }
 
        restore_flags(flags);
 
@@ -1752,6 +1959,95 @@ int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
        return FAILED;
 }
 
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
+/*
+ * Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : abort status
+ */
+static enum res_abort
+fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+       enum res_abort res = res_not_running;
+
+       if (queue_removecmd(&info->queues.issue, SCpnt)) {
+               /*
+                * The command was on the issue queue, and has not been
+                * issued yet.  We can remove the command from the queue,
+                * and acknowledge the abort.  Neither the devices nor the
+                * interface know about the command.
+                */
+               printk("on issue queue ");
+
+               res = res_success;
+       } else if (queue_removecmd(&info->queues.disconnected, SCpnt)) {
+               /*
+                * The command was on the disconnected queue.  Simply
+                * acknowledge the abort condition, and when the target
+                * reconnects, we will give it an ABORT message.  The
+                * target should then disconnect, and we will clear
+                * the busylun bit.
+                */
+               printk("on disconnected queue ");
+
+               res = res_success;
+       } else if (info->SCpnt == SCpnt) {
+               unsigned long flags;
+
+               printk("executing ");
+
+               save_flags(flags);
+               cli();
+               switch (info->scsi.phase) {
+               /*
+                * If the interface is idle, and the command is 'disconnectable',
+                * then it is the same as on the disconnected queue.  We simply
+                * remove all traces of the command.  When the target reconnects,
+                * we will give it an ABORT message since the command could not
+                * be found.  When the target finally disconnects, we will clear
+                * the busylun bit.
+                */
+               case PHASE_IDLE:
+                       if (info->scsi.disconnectable) {
+                               info->scsi.disconnectable = 0;
+                               info->SCpnt = NULL;
+                               res = res_success;
+                       }
+                       break;
+
+               /*
+                * If the command has connected and done nothing futher,
+                * simply force a disconnect.  We also need to clear the
+                * busylun bit.
+                */
+               case PHASE_SELECTION:
+//                     info->SCpnt = NULL;
+//                     res = res_success_clear;
+//                     break;
+
+               default:
+                       res = res_snooze;
+                       break;
+               }
+               restore_flags(flags);
+       } else if (info->origSCpnt == SCpnt) {
+               /*
+                * The command will be executed next, but a command
+                * is currently using the interface.  This is similar to
+                * being on the issue queue, except the busylun bit has
+                * been set.
+                */
+               info->origSCpnt = NULL;
+               printk("waiting for execution ");
+               res = res_success_clear;
+       } else
+               printk("unknown ");
+
+       return res;
+}
+
 /* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
  * Purpose : abort a command if something horrible happens.
  * Params  : SCpnt - Command that is believed to be causing a problem.
@@ -1769,46 +2065,51 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
        print_debug_list();
        fas216_dumpstate(info);
        fas216_dumpinfo(info);
-       printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no);
 
-       do {
-               /* If command is waiting in the issue queue, then we can
-                * simply remove the command and return abort status
-                */
-               if (queue_removecmd(&info->queues.issue, SCpnt)) {
-                       SCpnt->result = DID_ABORT << 16;
-                       SCpnt->scsi_done(SCpnt);
-                       printk("command on issue queue");
-                       result = SCSI_ABORT_SUCCESS;
-                       break;
-               }
+       printk(KERN_WARNING "scsi%d: abort ", info->host->host_no);
 
-               /* If the command is on the disconencted queue, we need to
-                * reconnect to the device
-                */
-               if (queue_cmdonqueue(&info->queues.disconnected, SCpnt))
-                       printk("command on disconnected queue");
+       switch (fas216_do_abort(info, SCpnt)) {
+       /*
+        * We managed to find the command and cleared it out.
+        * We do not expect the command to be executing on the
+        * target, but we have set the busylun bit.
+        */
+       case res_success_clear:
+               printk("clear ");
+               clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
 
-               /* If the command is connected, we need to flag that the
-                * command needs to be aborted
-                */
-               if (info->SCpnt == SCpnt)
-                       printk("command executing");
+       /*
+        * We found the command, and cleared it out.  Either
+        * the command is still known to be executing on the
+        * target, or the busylun bit is not set.
+        */
+       case res_success:
+               printk("success\n");
+               SCpnt->result = DID_ABORT << 16;
+               SCpnt->scsi_done(SCpnt);
+               result = SCSI_ABORT_SUCCESS;
+               break;
 
-               /* If the command is pending for execution, then again
-                * this is simple - we remove it and report abort status
-                */
-               if (info->origSCpnt == SCpnt) {
-                       info->origSCpnt = NULL;
-                       SCpnt->result = DID_ABORT << 16;
-                       SCpnt->scsi_done(SCpnt);
-                       printk("command waiting for execution");
-                       result = SCSI_ABORT_SUCCESS;
-                       break;
-               }
-       } while (0);
+       /*
+        * We did find the command, but unfortunately we couldn't
+        * unhook it from ourselves.  Wait some more, and if it
+        * still doesn't complete, reset the interface.
+        */
+       case res_snooze:
+               printk("snooze\n");
+               result = SCSI_ABORT_SNOOZE;
+               break;
 
-       printk("\n");
+       /*
+        * The command could not be found (either because it completed,
+        * or it got dropped.
+        */
+       default:
+       case res_not_running:
+               result = SCSI_ABORT_SNOOZE;
+               printk("not running\n");
+               break;
+       }
 
        return result;
 }
@@ -1819,7 +2120,7 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
  */
 static void fas216_reset_state(FAS216_Info *info)
 {
-       syncneg_t negstate;
+       neg_t sync_state, wide_state;
        int i;
 
        fas216_checkmagic(info, "fas216_reset_state");
@@ -1833,26 +2134,37 @@ static void fas216_reset_state(FAS216_Info *info)
        info->scsi.reconnected.lun = 0;
        info->scsi.reconnected.tag = 0;
        info->scsi.disconnectable = 0;
-       info->scsi.last_message = 0;
        info->scsi.aborting = 0;
        info->scsi.phase = PHASE_IDLE;
-       info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
+       info->scsi.async_stp =
+                       fas216_syncperiod(info, info->ifcfg.asyncperiod);
+
+       if (info->ifcfg.wide_max_size == 0)
+               wide_state = neg_invalid;
+       else
+#ifdef SCSI2_WIDE
+               wide_state = neg_wait;
+#else
+               wide_state = neg_invalid;
+#endif
 
        if (info->host->dma_channel == NO_DMA || !info->dma.setup)
-               negstate = syncneg_invalid;
+               sync_state = neg_invalid;
        else
 #ifdef SCSI2_SYNC
-               negstate = syncneg_start;
+               sync_state = neg_wait;
 #else
-               negstate = syncneg_invalid;
+               sync_state = neg_invalid;
 #endif
 
        for (i = 0; i < 8; i++) {
-               info->device[i].disconnect_ok = info->ifcfg.disconnect_ok;
-               info->device[i].negstate = negstate;
-               info->device[i].period = info->ifcfg.asyncperiod / 4;
-               info->device[i].stp = info->scsi.async_stp;
-               info->device[i].sof = 0;
+               info->device[i].disconnect_ok   = info->ifcfg.disconnect_ok;
+               info->device[i].sync_state      = sync_state;
+               info->device[i].wide_state      = wide_state;
+               info->device[i].period          = info->ifcfg.asyncperiod / 4;
+               info->device[i].stp             = info->scsi.async_stp;
+               info->device[i].sof             = 0;
+               info->device[i].wide_xfer       = 0;
        }
 }
 
@@ -1908,9 +2220,11 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
        info->stats.resets += 1;
 
        print_debug_list();
-       printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no);
+       printk(KERN_WARNING "scsi%d: reset ", info->host->host_no);
        if (SCpnt)
-               printk(" for target %d ", SCpnt->target);
+               printk("for target %d ", SCpnt->target);
+
+       printk("\n");
 
        outb(info->scsi.cfg[3], REG_CNTL3(info));
 
@@ -1963,8 +2277,6 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
                SCpnt->scsi_done(SCpnt);
        }
 
-       printk("\n");
-
        return result | SCSI_RESET_SUCCESS;
 }
 
@@ -2083,6 +2395,49 @@ int fas216_release(struct Scsi_Host *instance)
        return 0;
 }
 
+int fas216_print_stats(FAS216_Info *info, char *buffer)
+{
+       return sprintf(buffer,
+                       "Queued commands: %-10u   Issued commands: %-10u\n"
+                       "Done commands  : %-10u   Reads          : %-10u\n"
+                       "Writes         : %-10u   Others         : %-10u\n"
+                       "Disconnects    : %-10u   Aborts         : %-10u\n"
+                       "Resets         : %-10u\n",
+                       info->stats.queues,      info->stats.removes,
+                       info->stats.fins,        info->stats.reads,
+                       info->stats.writes,      info->stats.miscs,
+                       info->stats.disconnects, info->stats.aborts,
+                       info->stats.resets);
+}
+
+int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
+{
+       struct fas216_device *dev = &info->device[scd->id];
+       int len = 0;
+       char *p;
+
+       proc_print_scsidevice(scd, buffer, &len, 0);
+       p = buffer + len;
+
+       p += sprintf(p, "  Extensions: ");
+
+       if (scd->tagged_supported)
+               p += sprintf(p, "TAG %sabled [%d] ",
+                            scd->tagged_queue ? "en" : "dis",
+                            scd->current_tag);
+
+       p += sprintf(p, "\n  Transfers : %d-bit ",
+                    8 << dev->wide_xfer);
+
+       if (dev->sof)
+               p += sprintf(p, "sync offset %d, %d ns\n",
+                               dev->sof, dev->period * 4);
+       else
+               p += sprintf(p, "async\n");
+
+       return p - buffer;
+}
+
 EXPORT_SYMBOL(fas216_init);
 EXPORT_SYMBOL(fas216_abort);
 EXPORT_SYMBOL(fas216_reset);
@@ -2094,7 +2449,8 @@ EXPORT_SYMBOL(fas216_eh_abort);
 EXPORT_SYMBOL(fas216_eh_device_reset);
 EXPORT_SYMBOL(fas216_eh_bus_reset);
 EXPORT_SYMBOL(fas216_eh_host_reset);
-
+EXPORT_SYMBOL(fas216_print_stats);
+EXPORT_SYMBOL(fas216_print_device);
 
 #ifdef MODULE
 int init_module(void)
index 6518fbb422166d7d443294a31d505ea303d10e7c..351666638edce50f314ca238add371ac5be06e4d 100644 (file)
@@ -40,6 +40,7 @@
 #define CMD_TRANSFERINFO       0x10
 #define CMD_INITCMDCOMPLETE    0x11
 #define CMD_MSGACCEPTED                0x12
+#define CMD_PADBYTES           0x18
 #define CMD_SETATN             0x1a
 #define CMD_RSETATN            0x1b
 
 typedef enum {
        PHASE_IDLE,                                     /* we're not planning on doing anything */
        PHASE_SELECTION,                                /* selecting a device                   */
+       PHASE_SELSTEPS,                                 /* selection with command steps         */
+       PHASE_COMMAND,                                  /* command sent                         */
        PHASE_MESSAGESENT,                              /* selected, and we're sending cmd      */
        PHASE_RECONNECTED,                              /* reconnected                          */
        PHASE_DATAOUT,                                  /* data out to device                   */
        PHASE_DATAIN,                                   /* data in from device                  */
        PHASE_MSGIN,                                    /* message in from device               */
-       PHASE_MSGOUT,                                   /* message out to device                */
-       PHASE_AFTERMSGOUT,                              /* after message out phase              */
+       PHASE_MSGIN_DISCONNECT,                         /* disconnecting from bus               */
+       PHASE_MSGOUT,                                   /* after message out phase              */
+       PHASE_MSGOUT_EXPECT,                            /* expecting message out                */
        PHASE_STATUS,                                   /* status from device                   */
-       PHASE_DISCONNECT,                               /* disconnecting from bus               */
        PHASE_DONE                                      /* Command complete                     */
 } phase_t;
 
@@ -197,13 +200,15 @@ typedef enum {
 } fasdmatype_t;
 
 typedef enum {
-       syncneg_start,                                  /* Negociate with device for Sync xfers */
-       syncneg_sent,                                   /* Sync Xfer negociation sent           */
-       syncneg_complete,                               /* Sync Xfer complete                   */
-       syncneg_invalid                                 /* Sync Xfer not supported              */
-} syncneg_t;
+       neg_wait,                                       /* Negociate with device                */
+       neg_inprogress,                                 /* Negociation sent                     */
+       neg_complete,                                   /* Negociation complete                 */
+       neg_targcomplete,                               /* Target completed negociation         */
+       neg_invalid                                     /* Negociation not supported            */
+} neg_t;
 
 #define MAGIC  0x441296bdUL
+#define NR_MSGS        8
 
 typedef struct {
        unsigned long           magic_start;
@@ -231,7 +236,7 @@ typedef struct {
                MsgQueue_t      msgs;                   /* message queue for connected device   */
 
                unsigned int    async_stp;              /* Async transfer STP value             */
-               unsigned short  last_message;           /* last message to be sent              */
+               unsigned char   msgin_fifo;             /* bytes in fifo at time of message in  */
 
                unsigned char   disconnectable:1;       /* this command can be disconnected     */
                unsigned char   aborting:1;             /* aborting command                     */
@@ -255,6 +260,7 @@ typedef struct {
                unsigned char   clockrate;              /* clock rate of FAS device (MHz)       */
                unsigned char   select_timeout;         /* timeout (R5)                         */
                unsigned char   sync_max_depth;         /* Synchronous xfer max fifo depth      */
+               unsigned char   wide_max_size;          /* Maximum wide transfer size           */
                unsigned char   cntl3;                  /* Control Reg 3                        */
                unsigned int    asyncperiod;            /* Async transfer period (ns)           */
                unsigned int    disconnect_ok:1;        /* Disconnects allowed?                 */
@@ -267,12 +273,14 @@ typedef struct {
        } queues;
 
        /* per-device info */
-       struct {
+       struct fas216_device {
                unsigned char   disconnect_ok:1;        /* device can disconnect                */
-               unsigned int    period;                 /* sync xfer period (*4ns)              */
+               unsigned char   period;                 /* sync xfer period in (*4ns)           */
                unsigned char   stp;                    /* synchronous transfer period          */
                unsigned char   sof;                    /* synchronous offset register          */
-               syncneg_t       negstate;               /* synchronous transfer mode            */
+               unsigned char   wide_xfer;              /* currently negociated wide transfer   */
+               neg_t           sync_state;             /* synchronous transfer mode            */
+               neg_t           wide_state;             /* wide transfer mode                   */
        } device[8];
        unsigned char   busyluns[8];                    /* array of bits indicating LUNs busy   */
 
@@ -340,6 +348,9 @@ extern void fas216_intr (struct Scsi_Host *instance);
  */
 extern int fas216_release (struct Scsi_Host *instance);
 
+extern int fas216_print_stats(FAS216_Info *info, char *buffer);
+extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
+
 /* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
  * Purpose : abort this command
  * Params  : SCpnt - command to abort
index 7621b4d2bdcf2cd7edd3ffc4a92c78af48ea0fd1..f28784496c20c32c0196ad87729a31099638f82a 100644 (file)
@@ -83,45 +83,25 @@ int msgqueue_msglength(MsgQueue_t *msgq)
        int length = 0;
 
        for (mq = msgq->qe; mq; mq = mq->next)
-               length += mq->length;
+               length += mq->msg.length;
 
        return length;
 }
 
 /*
- * Function: char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return a message & its length
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message
  * Params  : msgq   - queue to obtain message from
- *          length - pointer to int for message length
+ *        : msgno  - message number
  * Returns : pointer to message string, or NULL
  */
-char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length)
+struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
 {
        struct msgqueue_entry *mq;
 
-       if ((mq = msgq->qe) != NULL) {
-               msgq->qe = mq->next;
-               mqe_free(msgq, mq);
-               *length = mq->length;
-       }
-
-       return mq ? mq->msg : NULL;
-}
-
-/*
- * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return next message & length without removing it from the list
- * Params  : msgq   - queue to obtain message from
- *         : length - pointer to int for message length
- * Returns : pointer to message string, or NULL
- */
-char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
-{
-       struct msgqueue_entry *mq = msgq->qe;
-
-       *length = mq ? mq->length : 0;
+       for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
 
-       return mq ? mq->msg : NULL;
+       return mq ? &mq->msg : NULL;
 }
 
 /*
@@ -143,10 +123,11 @@ int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
 
                va_start(ap, length);
                for (i = 0; i < length; i++)
-                       mq->msg[i] = va_arg(ap, unsigned char);
+                       mq->msg.msg[i] = va_arg(ap, unsigned char);
                va_end(ap);
 
-               mq->length = length;
+               mq->msg.length = length;
+               mq->msg.fifo = 0;
                mq->next = NULL;
 
                mqp = &msgq->qe;
@@ -178,8 +159,7 @@ void msgqueue_flush(MsgQueue_t *msgq)
 EXPORT_SYMBOL(msgqueue_initialise);
 EXPORT_SYMBOL(msgqueue_free);
 EXPORT_SYMBOL(msgqueue_msglength);
-EXPORT_SYMBOL(msgqueue_getnextmsg);
-EXPORT_SYMBOL(msgqueue_peeknextmsg);
+EXPORT_SYMBOL(msgqueue_getmsg);
 EXPORT_SYMBOL(msgqueue_addmsg);
 EXPORT_SYMBOL(msgqueue_flush);
 
index cca30255c36d757c26d6e331350f66c07879e1c5..8016dcf4e31f56be4e66aef82e1542bae3cf8959 100644 (file)
@@ -6,9 +6,14 @@
 #ifndef MSGQUEUE_H
 #define MSGQUEUE_H
 
-struct msgqueue_entry {
+struct message {
     char msg[8];
     int length;
+    int fifo;
+};
+
+struct msgqueue_entry {
+    struct message msg;
     struct msgqueue_entry *next;
 };
 
@@ -21,60 +26,51 @@ typedef struct {
 } MsgQueue_t;
 
 /*
- * Function: void msgqueue_initialise (MsgQueue_t *msgq)
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
  * Purpose : initialise a message queue
  * Params  : msgq - queue to initialise
  */
-extern void msgqueue_initialise (MsgQueue_t *msgq);
+extern void msgqueue_initialise(MsgQueue_t *msgq);
 
 /*
- * Function: void msgqueue_free (MsgQueue_t *msgq)
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
  * Purpose : free a queue
  * Params  : msgq - queue to free
  */
-extern void msgqueue_free (MsgQueue_t *msgq);
+extern void msgqueue_free(MsgQueue_t *msgq);
 
 /*
- * Function: int msgqueue_msglength (MsgQueue_t *msgq)
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
  * Purpose : calculate the total length of all messages on the message queue
  * Params  : msgq - queue to examine
  * Returns : number of bytes of messages in queue
  */
-extern int msgqueue_msglength (MsgQueue_t *msgq);
+extern int msgqueue_msglength(MsgQueue_t *msgq);
 
 /*
- * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length)
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
  * Purpose : return a message & its length
  * Params  : msgq   - queue to obtain message from
- *          length - pointer to int for message length
- * Returns : pointer to message string, or NULL
- */
-extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length);
-
-/*
- * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return next message & length without removing it from the list
- * Params  : msgq   - queue to obtain message from
- *         : length - pointer to int for message length
+ *         : msgno  - message number
  * Returns : pointer to message string, or NULL
  */
-extern char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length);
+extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno);
 
 /*
- * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...)
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
  * Purpose : add a message onto a message queue
  * Params  : msgq   - queue to add message on
  *          length - length of message
  *          ...    - message bytes
  * Returns : != 0 if successful
  */
-extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...);
+extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...);
 
 /*
- * Function: void msgqueue_flush (MsgQueue_t *msgq)
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
  * Purpose : flush all messages from message queue
  * Params  : msgq - queue to flush
  */
-extern void msgqueue_flush (MsgQueue_t *msgq);
+extern void msgqueue_flush(MsgQueue_t *msgq);
 
 #endif
index caae8a8ba04026567b195a380fbbae8969bf32ed..95dbc3050153cfc75275d17f5130b853a8420189 100644 (file)
@@ -114,6 +114,8 @@ static const expansioncard_ops_t powertecscsi_ops = {
        powertecscsi_irqenable,
        powertecscsi_irqdisable,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
@@ -271,8 +273,9 @@ powertecscsi_detect(Scsi_Host_Template *tpnt)
                info->info.ifcfg.select_timeout = 255;
                info->info.ifcfg.asyncperiod    = POWERTEC_ASYNC_PERIOD;
                info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH;
-               info->info.ifcfg.cntl3          = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+               info->info.ifcfg.cntl3          = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK;
                info->info.ifcfg.disconnect_ok  = 1;
+               info->info.ifcfg.wide_max_size  = 0;
                info->info.dma.setup            = powertecscsi_dma_setup;
                info->info.dma.pseudo           = NULL;
                info->info.dma.stop             = powertecscsi_dma_stop;
@@ -443,31 +446,12 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
                        host->io_port, host->irq, host->dma_channel,
                        info->info.scsi.type, info->control.terms ? "on" : "off");
 
-       pos += sprintf(buffer+pos,
-                       "Queued commands: %-10u   Issued commands: %-10u\n"
-                       "Done commands  : %-10u   Reads          : %-10u\n"
-                       "Writes         : %-10u   Others         : %-10u\n"
-                       "Disconnects    : %-10u   Aborts         : %-10u\n"
-                       "Resets         : %-10u\n",
-                       info->info.stats.queues,      info->info.stats.removes,
-                       info->info.stats.fins,        info->info.stats.reads,
-                       info->info.stats.writes,      info->info.stats.miscs,
-                       info->info.stats.disconnects, info->info.stats.aborts,
-                       info->info.stats.resets);
+       pos += fas216_print_stats(&info->info, buffer + pos);
 
-       pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+       pos += sprintf (buffer+pos, "\nAttached devices:\n");
 
        for (scd = host->host_queue; scd; scd = scd->next) {
-               int len;
-
-               proc_print_scsidevice (scd, buffer, &len, pos);
-               pos += len;
-               pos += sprintf (buffer+pos, "Extensions: ");
-               if (scd->tagged_supported)
-                       pos += sprintf (buffer+pos, "TAG %sabled [%d] ",
-                                   scd->tagged_queue ? "en" : "dis",
-                                   scd->current_tag);
-               pos += sprintf (buffer+pos, "\n");
+               pos += fas216_print_device(&info->info, scd, buffer + pos);
 
                if (pos + begin < offset) {
                        begin += pos;
index b8f5ba0ad00c8815d4eee80edb6e485214d10d09..31e9d3dfcb88932a069483fbc5cfced652031ba1 100644 (file)
@@ -55,6 +55,7 @@ int queue_initialise (Queue_t *queue)
                        q->magic = QUEUE_MAGIC_FREE;
                        q->SCpnt = NULL;
                }
+               q -= 1;
                q->next = NULL;
        }
 
index 47fc9eac1b79674c077688e5c95567fc427bb2af..a9b9a000f0a364a03bbceebab7ce63be9ca11d49 100644 (file)
@@ -38,16 +38,16 @@ else
       bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
       bool '   Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
       if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
-        bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
+        bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
+        if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+          bool '     Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
+        fi
         bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
         bool '     AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
-        if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
-          bool '     Use DMA by default when available' CONFIG_IDEDMA_AUTO
-        fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
           bool '     Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX
-          if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+          if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
             bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
             bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
             bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
@@ -66,7 +66,7 @@ else
           fi
         fi
       fi
-      if [ "$CONFIG_PPC" = "y" ]; then
+      if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
       fi
     fi
@@ -75,11 +75,25 @@ else
         if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
           bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
           if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-            define_bool CONFIG_BLK_DEV_IDEDMA y
             bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
           fi
        fi
     fi
+    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+        bool '   ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE
+        if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then
+          bool '     ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS
+          if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+            bool '     Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO
+          fi
+        fi
+        bool '   RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE
+    fi
+    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
+         "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
+         "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+      define_bool CONFIG_BLK_DEV_IDEDMA y
+    fi
     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
       comment 'Note: most of these also require special kernel boot parameters'
@@ -170,7 +184,8 @@ if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
      "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
      "$CONFIG_BLK_DEV_HPT343" = "y" -o \
-     "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+     "$CONFIG_BLK_DEV_PIIX" = "y" -o \
+     "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
   define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
   define_bool CONFIG_BLK_DEV_IDE_MODES n
diff --git a/drivers/block/icside.c b/drivers/block/icside.c
new file mode 100644 (file)
index 0000000..299bce7
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * linux/drivers/block/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ *  08-Jun-1996        RMK     Created
+ *  12-Sep-1997        RMK     Added interrupt enable/disable
+ *  17-Apr-1999        RMK     Added support for V6 EASI
+ *  22-May-1999        RMK     Added support for V6 DMA
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS        2
+
+#define ICS_IDENT_OFFSET               0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT          0x000
+#define ICS_ARCIN_V5_INTROFFSET                0x001
+#define ICS_ARCIN_V5_IDEOFFSET         0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET      0xae0
+#define ICS_ARCIN_V5_IDESTEPPING       4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1       0x800
+#define ICS_ARCIN_V6_INTROFFSET_1      0x880
+#define ICS_ARCIN_V6_INTRSTAT_1                0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1    0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2       0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2      0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2                0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2    0xce0
+#define ICS_ARCIN_V6_IDESTEPPING       4
+
+struct cardinfo {
+       unsigned int dataoffset;
+       unsigned int ctrloffset;
+       unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+       ICS_ARCIN_V5_IDEOFFSET,
+       ICS_ARCIN_V5_IDEALTOFFSET,
+       ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+       ICS_ARCIN_V6_IDEOFFSET_1,
+       ICS_ARCIN_V6_IDEALTOFFSET_1,
+       ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+       ICS_ARCIN_V6_IDEOFFSET_2,
+       ICS_ARCIN_V6_IDEALTOFFSET_2,
+       ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+       { MANU_ICS,  PROD_ICS_IDE  },
+       { MANU_ICS2, PROD_ICS2_IDE },
+       { 0xffff, 0xffff }
+};
+
+typedef enum {
+       ics_if_unknown,
+       ics_if_arcin_v5,
+       ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+       unsigned int memc_port = (unsigned int)ec->irq_data;
+       outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+       unsigned int memc_port = (unsigned int)ec->irq_data;
+       inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+       icside_irqenable_arcin_v5,
+       icside_irqdisable_arcin_v5,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+       outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+       outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+       inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+       inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+       unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+       return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+              inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+       icside_irqenable_arcin_v6,
+       icside_irqdisable_arcin_v6,
+       icside_irqpending_arcin_v6,
+       NULL,
+       NULL,
+       NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose  : identify IDE interface type
+ * Notes    : checks the description string
+ */
+static iftype_t icside_identifyif (struct expansion_card *ec)
+{
+       unsigned int addr;
+       iftype_t iftype;
+       int id = 0;
+
+       iftype = ics_if_unknown;
+
+       addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+       id = inb (addr) & 1;
+       id |= (inb (addr + 1) & 1) << 1;
+       id |= (inb (addr + 2) & 1) << 2;
+       id |= (inb (addr + 3) & 1) << 3;
+
+       switch (id) {
+       case 0: /* A3IN */
+               printk("icside: A3IN unsupported\n");
+               break;
+
+       case 1: /* A3USER */
+               printk("icside: A3USER unsupported\n");
+               break;
+
+       case 3: /* ARCIN V6 */
+               printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+               iftype = ics_if_arcin_v6;
+               break;
+
+       case 15:/* ARCIN V5 (no id) */
+               printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+               iftype = ics_if_arcin_v5;
+               break;
+
+       default:/* we don't know - complain very loudly */
+               printk("icside: ***********************************\n");
+               printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+               printk("icside: ***********************************\n");
+               printk("icside: please report this to linux@arm.linux.org.uk\n");
+               printk("icside: defaulting to ARCIN V5\n");
+               iftype = ics_if_arcin_v5;
+               break;
+       }
+
+       return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD
+ * DMA controllers.  There is only one DMA controller
+ * per card, which means that only one drive can be
+ * accessed at one time.  NOTE! We do not inforce that
+ * here, but we rely on the main IDE driver spotting
+ * that both interfaces use the same IRQ, which should
+ * guarantee this.
+ *
+ * We are limited by the drives IOR/IOW pulse time.
+ * The closest that we can get to the requirements is
+ * a type C cycle for both mode 1 and mode 2.  However,
+ * this does give a burst of 8MB/s.
+ *
+ * This has been tested with a couple of Conner
+ * Peripherals 1080MB CFS1081A drives, one on each
+ * interface, which deliver about 2MB/s each.  I
+ * believe that this is limited by the lack of
+ * on-board drive cache.
+ */
+#define TABLE_SIZE 2048
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int reading)
+{
+       struct request *rq = HWGROUP(drive)->rq;
+       struct buffer_head *bh = rq->bh;
+       unsigned long addr, size;
+       unsigned char *virt_addr;
+       unsigned int count = 0;
+       dmasg_t *sg = (dmasg_t *)HWIF(drive)->dmatable;
+
+       do {
+               if (bh == NULL) {
+                       /* paging requests have (rq->bh == NULL) */
+                       virt_addr = rq->buffer;
+                       addr = virt_to_bus (virt_addr);
+                       size = rq->nr_sectors << 9;
+               } else {
+                       /* group sequential buffers into one large buffer */
+                       virt_addr = bh->b_data;
+                       addr = virt_to_bus (virt_addr);
+                       size = bh->b_size;
+                       while ((bh = bh->b_reqnext) != NULL) {
+                               if ((addr + size) != virt_to_bus (bh->b_data))
+                                       break;
+                               size += bh->b_size;
+                       }
+               }
+
+               if (addr & 3) {
+                       printk("%s: misaligned DMA buffer\n", drive->name);
+                       return 0;
+               }
+
+               if (size) {
+                       if (reading)
+                               dma_cache_inv((unsigned int)virt_addr, size);
+                       else
+                               dma_cache_wback((unsigned int)virt_addr, size);
+               }
+
+               sg[count].address = addr;
+               sg[count].length = size;
+               if (++count >= (TABLE_SIZE / sizeof(dmasg_t))) {
+                       printk("%s: DMA table too small\n", drive->name);
+                       return 0;
+               }
+       } while (bh != NULL);
+
+       if (!count)
+               printk("%s: empty DMA table?\n", drive->name);
+
+       return count;
+}
+
+static int
+icside_config_drive(ide_drive_t *drive, int mode)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       int speed, err;
+
+       if (mode == 2) {
+               speed = XFER_MW_DMA_2;
+               drive->drive_data = 250;
+       } else {
+               speed = XFER_MW_DMA_1;
+               drive->drive_data = 250;
+       }
+
+       /*
+        * Don't use ide_wait_cmd here - it will
+        * attempt to set_geometry and recalibrate,
+        * but for some reason these don't work at
+        * this point (lost interrupt).
+        */
+       SELECT_DRIVE(hwif, drive);
+       OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+       OUT_BYTE(speed, IDE_NSECTOR_REG);
+       OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+       OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+       err = ide_wait_stat(drive, DRIVE_READY,
+                           BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+
+       if (err == 0) {
+               drive->id->dma_mword &= 0x00ff;
+               drive->id->dma_mword |= 256 << mode;
+       } else
+               drive->drive_data = 0;
+
+       return err;
+}
+
+static int
+icside_dma_check(ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+       ide_hwif_t *hwif = HWIF(drive);
+       int autodma = hwif->autodma;
+
+       if (id && (id->capability & 1) && autodma) {
+               int dma_mode = 0;
+
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive))
+                       return hwif->dmaproc(ide_dma_off, drive);
+
+               /* Enable DMA on any drive that has
+                * UltraDMA (mode 0/1/2) enabled
+                */
+               if (id->field_valid & 4 && id->dma_ultra & 7)
+                       dma_mode = 2;
+               
+               /* Enable DMA on any drive that has mode1
+                * or mode2 multiword DMA enabled
+                */
+               if (id->field_valid & 2 && id->dma_mword & 6)
+                       dma_mode = id->dma_mword & 4 ? 2 : 1;
+
+               /* Consult the list of known "good" drives */
+               if (ide_dmaproc(ide_dma_good_drive, drive))
+                       dma_mode = 1;
+
+               if (dma_mode && icside_config_drive(drive, dma_mode) == 0)
+                       return hwif->dmaproc(ide_dma_on, drive);
+       }
+       return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+static int
+icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       int count, reading = 0;
+
+       switch (func) {
+       case ide_dma_check:
+               return icside_dma_check(drive);
+
+       case ide_dma_read:
+               reading = 1;
+       case ide_dma_write:
+               count = icside_build_dmatable(drive, reading);
+               if (!count)
+                       return 1;
+               disable_dma(hwif->hw.dma);
+
+               /* Route the DMA signals to
+                * to the correct interface.
+                */
+               outb(hwif->select_data, hwif->config_data);
+
+               /* Select the correct timing
+                * for this drive
+                */
+               set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+               set_dma_sg(hwif->hw.dma, (dmasg_t *)hwif->dmatable, count);
+               set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
+                            : DMA_MODE_WRITE);
+
+               drive->waiting_for_dma = 1;
+               if (drive->media != ide_disk)
+                       return 0;
+
+               ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+               OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
+                        IDE_COMMAND_REG);
+
+       case ide_dma_begin:
+               enable_dma(hwif->hw.dma);
+               return 0;
+
+       case ide_dma_end:
+               drive->waiting_for_dma = 0;
+               disable_dma(hwif->hw.dma);
+               return get_dma_residue(hwif->hw.dma) != 0;
+
+       case ide_dma_test_irq:
+               return inb((unsigned long)hwif->hw.priv) & 1;
+
+       default:
+               return ide_dmaproc(func, drive);
+       }
+}
+
+static unsigned long
+icside_alloc_dmatable(void)
+{
+       static unsigned long dmatable;
+       static unsigned int leftover;
+       unsigned long table;
+
+       if (leftover < TABLE_SIZE) {
+#if PAGE_SIZE == TABLE_SIZE * 2
+               dmatable = __get_free_pages(GFP_KERNEL, 1);
+               leftover = PAGE_SIZE;
+#else
+               dmatable = kmalloc(TABLE_SIZE, GFP_KERNEL);
+               leftover = TABLE_SIZE;
+#endif
+       }
+
+       table = dmatable;
+       if (table) {
+               dmatable += TABLE_SIZE;
+               leftover -= TABLE_SIZE;
+       }
+
+       return table;
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+       unsigned long table = icside_alloc_dmatable();
+
+       printk("    %s: SG-DMA", hwif->name);
+
+       if (!table)
+               printk(" -- ERROR, unable to allocate DMA table\n");
+       else {
+               hwif->dmatable = (void *)table;
+               hwif->dmaproc = icside_dmaproc;
+               hwif->autodma = autodma;
+
+               printk(" capable%s\n", autodma ?
+                       ", auto-enable" : "");
+       }
+
+       return hwif->dmatable != NULL;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+       ide_hwif_t *hwif;
+       int index;
+
+       for (index = 0; index < MAX_HWIFS; ++index) {
+               hwif = &ide_hwifs[index];
+               if (hwif->hw.io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+                       goto found;
+       }
+
+       for (index = 0; index < MAX_HWIFS; ++index) {
+               hwif = &ide_hwifs[index];
+               if (!hwif->hw.io_ports[IDE_DATA_OFFSET])
+                       goto found;
+       }
+
+       return NULL;
+found:
+       return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+       unsigned long port = base + info->dataoffset;
+       ide_hwif_t *hwif;
+
+       hwif = icside_find_hwif(base);
+       if (hwif) {
+               int i;
+
+               memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+               for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+                       hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+                       port += 1 << info->stepping;
+               }
+               hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+               hwif->hw.irq  = irq;
+               hwif->hw.dma  = NO_DMA;
+               hwif->noprobe = 0;
+               hwif->chipset = ide_acorn;
+       }
+
+       return hwif;
+}
+
+static int icside_register_v5(struct expansion_card *ec, int autodma)
+{
+       unsigned long slot_port;
+       ide_hwif_t *hwif;
+
+       slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+       ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+       ec->irqmask  = 1;
+       ec->irq_data = (void *)slot_port;
+       ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+       /*
+        * Be on the safe side - disable interrupts
+        */
+       inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+       hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+       return hwif ? 0 : -1;
+}
+
+static int icside_register_v6(struct expansion_card *ec, int autodma)
+{
+       unsigned long slot_port, port;
+       ide_hwif_t *hwif, *mate;
+       int sel = 0;
+
+       slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+       port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+       if (port == 0)
+               port = slot_port;
+       else
+               sel = 1 << 5;
+
+       outb(sel, slot_port);
+
+       ec->irq_data = (void *)port;
+       ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+       /*
+        * Be on the safe side - disable interrupts
+        */
+       inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+       inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+       hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+       mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+       if (ec->dma != NO_DMA) {
+               if (request_dma(ec->dma, hwif->name))
+                       goto no_dma;
+
+               if (hwif) {
+                       hwif->config_data = slot_port;
+                       hwif->select_data = sel;
+                       hwif->hw.dma  = ec->dma;
+                       hwif->hw.priv = (void *)
+                                       (port + ICS_ARCIN_V6_INTRSTAT_1);
+                       hwif->channel = 0;
+                       icside_setup_dma(hwif, autodma);
+               }
+               if (mate) {
+                       mate->config_data = slot_port;
+                       mate->select_data = sel | 1;
+                       mate->hw.dma  = ec->dma;
+                       mate->hw.priv = (void *)
+                                       (port + ICS_ARCIN_V6_INTRSTAT_2);
+                       mate->channel = 1;
+                       icside_setup_dma(mate, autodma);
+               }
+       }
+#endif
+
+no_dma:
+       return hwif || mate ? 0 : -1;
+}
+
+int icside_init(void)
+{
+       int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+       autodma = 1;
+#endif
+
+       ecard_startfind ();
+
+       do {
+               struct expansion_card *ec;
+               int result;
+
+               ec = ecard_find(0, icside_cids);
+               if (ec == NULL)
+                       break;
+
+               ecard_claim(ec);
+
+               switch (icside_identifyif(ec)) {
+               case ics_if_arcin_v5:
+                       result = icside_register_v5(ec, autodma);
+                       break;
+
+               case ics_if_arcin_v6:
+                       result = icside_register_v6(ec, autodma);
+                       break;
+
+               default:
+                       result = -1;
+                       break;
+               }
+
+               if (result)
+                       ecard_release(ec);
+       } while (1);
+
+       return 0;
+}
diff --git a/drivers/block/rapide.c b/drivers/block/rapide.c
new file mode 100644 (file)
index 0000000..468f2e3
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * linux/arch/arm/drivers/block/ide-rapide.c
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ *
+ * Changelog:
+ *  08-06-1996 RMK     Created
+ *  13-04-1998 RMK     Added manufacturer and product IDs
+ */
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+
+#include <asm/ecard.h>
+
+static const card_ids rapide_cids[] = {
+       { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+       { 0xffff, 0xffff }
+};
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS];
+
+static inline int rapide_register(struct expansion_card *ec)
+{
+       unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+       hw_regs_t hw;
+
+       int i;
+
+       memset(&hw, 0, sizeof(hw));
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw.io_ports[i] = (ide_ioreg_t)port;
+               port += 1 << 4;
+       }
+       hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+       hw.irq = ec->irq;
+
+       return ide_register_hw(&hw, NULL);
+}
+
+int rapide_init(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_ECARDS; i++)
+               ec[i] = NULL;
+
+       ecard_startfind();
+
+       for (i = 0; ; i++) {
+               if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
+                       break;
+
+               ecard_claim(ec[i]);
+               result[i] = rapide_register(ec[i]);
+       }
+       for (i = 0; i < MAX_ECARDS; i++)
+               if (ec[i] && result[i] < 0) {
+                       ecard_release(ec[i]);
+                       ec[i] = NULL;
+       }
+       return 0;
+}
+
+#ifdef MODULE
+
+int init_module (void)
+{
+       return rapide_init();
+}
+
+void cleanup_module (void)
+{
+       int i;
+
+       for (i = 0; i < MAX_ECARDS; i++)
+               if (ec[i]) {
+                       unsigned long port;
+                       port = ecard_address(ec[i], ECARD_MEMC, 0);
+
+                       ide_unregister_port(port, ec[i]->irq, 16);
+                       ecard_release(ec[i]);
+                       ec[i] = NULL;
+               }
+}
+#endif
+
index aa37f146ce7ca0520a52739b40c05fca423a4e4c..4843ba5329a678a58c3af6f66f6447cf9bf02f1e 100644 (file)
@@ -143,14 +143,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_ETHERH),y)
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_ETHERH),m)
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
 ifeq ($(CONFIG_WD80x3),y)
 L_OBJS += wd.o
 CONFIG_8390_BUILTIN = y
@@ -171,14 +163,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_ETHERH),y)
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_ETHERH),m)
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
 ifeq ($(CONFIG_NE2K_PCI),y)
 L_OBJS += ne2k-pci.o
 CONFIG_8390_BUILTIN = y
index 4e1e3465d3306cbb90c12c0c3ab4dd354f43cfda..bd385ccf8e2bc307cefbefcb152d9d4ae059c209 100644 (file)
@@ -51,7 +51,7 @@ pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
                from = pci_devices;
        else
                from = from->next;
-       while (from && (from->vendor != vendor || from->device != device))
+       while (from && (from->vendor != vendor && vendor != PCI_ANY_ID || from->device != device && device != PCI_ANY_ID))
                from = from->next;
        return from;
 }
@@ -178,10 +178,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
 
                if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
                    /* some broken boards return 0 if a slot is empty: */
-                   l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
-                       is_multi = 0;
+                   l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
                        continue;
-               }
 
                dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
                memset(dev, 0, sizeof(*dev));
index ff5367d6dbbfe75839841e7a325f4b0542da612b..79d3945ef5f7164513199ea3bd2e26c7252f2cca 100644 (file)
 struct cs4215 {
        __u8    data[4];        /* Data mode: Time slots 5-8 */
        __u8    ctrl[4];        /* Ctrl mode: Time slots 1-4 */
-       __volatile__ struct dbri_mem td;
-       __volatile__ struct dbri_mem rd;
        __u8    onboard;
-       __u32   status;
-        __u32  version;
+       __u8    offset;         /* Bit offset from frame sync to time slot 1 */
+       volatile __u32  status;
+       volatile __u32  version;
 };
 
 
index 23afc72b4455aa83b41e1e955ad98a6e3c54e2f1..9f76c92e6d9eff97fd0ae804465f6ef5f9a28748 100644 (file)
 #define D_CMD  (1<<2)
 #define D_MM   (1<<3)
 #define D_USR  (1<<4)
+#define D_DESC (1<<5)
 
-/* static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; */
 static int dbri_debug = 0;
 MODULE_PARM(dbri_debug, "i");
 
+static int dbri_trace = 0;
+MODULE_PARM(dbri_trace, "i");
+#define tprintk(x) if(dbri_trace) printk x
+
 static char *cmds[] = { 
   "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
   "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
 };
 
-/* Bit hunting */
-#define dumpcmd {int i; for(i=0; i<n; i++) printk("DBRI: %x\n", dbri->dma->cmd[i]); }
-
 #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value)
 
 #else
 
 #define dprintk(a, x)
-#define dumpcmd
 #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value)
 
 #endif /* DBRI_DEBUG */
@@ -114,41 +114,42 @@ static int num_drivers = 0;
 ****************************************************************************
 ************** DBRI initialization and command synchronization *************
 ****************************************************************************
-*/
 
+Commands are sent to the DBRI by building a list of them in memory,
+then writing the address of the first list item to DBRI register 8.
+The list is terminated with a WAIT command, which can generate a
+CPU interrupt if required.
+
+Since the DBRI can run in parallel with the CPU, several means of
+synchronization present themselves.  The original scheme (Rudolf's)
+was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
+an interrupt signaled completion, and wait on a wait_queue if a routine
+attempted to cmdlock while the flag was set.  The problems arose when
+we tried to cmdlock from inside an interrupt handler, which might
+cause scheduling in an interrupt (if we waited), etc, etc
+
+A more sophisticated scheme might involve a circular command buffer
+or an array of command buffers.  A routine could fill one with
+commands and link it onto a list.  When a interrupt signaled
+completion of the current command buffer, look on the list for
+the next one.
+
+I've decided to implement something much simpler - after each command,
+the CPU waits for the DBRI to finish the command by polling the P bit
+in DBRI register 0.  I've tried to implement this in such a way
+that might make implementing a more sophisticated scheme easier.
+
+Every time a routine wants to write commands to the DBRI, it must
+first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
+in return.  After the commands have been writen, dbri_cmdsend() is
+called with the final pointer value.
+
+Something a little more clever is required if this code is ever run
+on an SMP machine.
 
-/*
- * Commands are sent to the DBRI by building a list of them in memory,
- * then writing the address of the first list item to DBRI register 8.
- * The list is terminated with a WAIT command, which can generate a
- * CPU interrupt if required.
- *
- * Since the DBRI can run asynchronously to the CPU, several means of
- * synchronization present themselves.  The original scheme (Rudolf's)
- * was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
- * an interrupt signaled completion, and wait on a wait_queue if a routine
- * attempted to cmdlock while the flag was set.  The problems arose when
- * we tried to cmdlock from inside an interrupt handler, which might
- * cause scheduling in an interrupt (if we waited), etc, etc
- *
- * A more sophisticated scheme might involve a circular command buffer
- * or an array of command buffers.  A routine could fill one with
- * commands and link it onto a list.  When a interrupt signaled
- * completion of the current command buffer, look on the list for
- * the next one.
- *
- * I've decided to implement something much simpler - after each command,
- * the CPU waits for the DBRI to finish the command by polling the P bit
- * in DBRI register 0.  I've tried to implement this in such a way
- * that might make implementing a more sophisticated scheme easier.
- *
- * Every time a routine wants to write commands to the DBRI, it must
- * first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
- * in return.  After the commands have been writen, dbri_cmdsend() is
- * called with the final pointer value.
- */
+*/
 
-static int dbri_locked = 0;                    /* XXX not SMP safe! XXX */
+static int dbri_locked = 0;
 
 static volatile int * dbri_cmdlock(struct dbri *dbri)
 {
@@ -159,9 +160,21 @@ static volatile int * dbri_cmdlock(struct dbri *dbri)
         return dbri->dma->cmd;
 }
 
+static void dbri_process_interrupt_buffer(struct dbri *);
+
 static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd)
 {
-        int maxloops = 1000000;
+       int MAXLOOPS = 1000000;
+       int maxloops = MAXLOOPS;
+       unsigned int flags;
+       volatile int * ptr;
+
+       for (ptr = dbri->dma->cmd; ptr < cmd; ptr ++) {
+               dprintk(D_CMD, ("DBRI cmd: %08x:%08x\n",
+                               (unsigned int) ptr, *ptr));
+       }
+
+       save_and_cli(flags);
 
         dbri_locked --;
         if (dbri_locked != 0) {
@@ -170,14 +183,25 @@ static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd)
                 printk("DBRI: Command buffer overflow! (bug in driver)\n");
         } else {
                 *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
-                *(cmd++) = DBRI_CMD(D_WAIT, 0, 0);
+               *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
+               dbri->wait_seen = 0;
                 dbri->regs->reg8 = (int)dbri->dma_dvma->cmd;
-                while ((maxloops--) > 0 && (dbri->regs->reg0 & D_P));
+               while ((--maxloops) > 0 && (dbri->regs->reg0 & D_P));
+               if (maxloops == 0) {
+                       printk("DBRI: Chip never completed command buffer\n");
+               } else {
+                       while ((--maxloops) > 0 && (! dbri->wait_seen))
+                               dbri_process_interrupt_buffer(dbri);
+                       if (maxloops == 0) {
+                               printk("DBRI: Chip never acked WAIT\n");
+                       } else {
+                               dprintk(D_INT, ("DBRI: Chip completed command buffer (%d)\n",
+                                               MAXLOOPS - maxloops));
+                       }
+               }
         }
 
-        if (maxloops == 0) {
-                printk("DBRI: Chip never completed command buffer\n");
-        }
+       restore_flags(flags);
 }
 
 static void dbri_reset(struct dbri *dbri)
@@ -198,7 +222,7 @@ static void dbri_detach(struct dbri *dbri)
        dbri_reset(dbri);
         free_irq(dbri->irq, dbri);
         sparc_free_io(dbri->regs, dbri->regs_size);
-        /* Should we release the DMA structure dbri->dma here? */
+       release_region((unsigned long) dbri->dma, sizeof(struct dbri_dma));
         kfree(dbri);
 }
 
@@ -242,6 +266,17 @@ static void dbri_initialize(struct dbri *dbri)
 ****************************************************************************
 *************************** DBRI interrupt handler *************************
 ****************************************************************************
+
+The DBRI communicates with the CPU mainly via a circular interrupt
+buffer.  When an interrupt is signaled, the CPU walks through the
+buffer and calls dbri_process_one_interrupt() for each interrupt word.
+Complicated interrupts are handled by dedicated functions (which
+appear first in this file).  Any pending interrupts can be serviced by
+calling dbri_process_interrupt_buffer(), which works even if the CPU's
+interrupts are disabled.  This function is used by dbri_cmdsend()
+to make sure we're synced up with the chip after each command sequence,
+even if we're running cli'ed.
+
 */
 
 
@@ -263,6 +298,7 @@ static __u32 reverse_bytes(__u32 b, int len)
         case 2:
                 b = ((b & 0xaaaaaaaa) >>  1) | ((b & 0x55555555) <<  1);
         case 1:
+       case 0:
                 break;
         default:
                 printk("DBRI reverse_bytes: unsupported length\n");
@@ -273,37 +309,39 @@ static __u32 reverse_bytes(__u32 b, int len)
 /* transmission_complete_intr()
  *
  * Called by main interrupt handler when DBRI signals transmission complete
- * on a pipe.
+ * on a pipe (interrupt triggered by the B bit in a transmit descriptor).
  *
  * Walks through the pipe's list of transmit buffer descriptors, releasing
- * each one's DMA buffer (if present) and signaling its callback routine
- * (if present), before flaging the descriptor available and proceeding
- * to the next one.
- *
- * Assumes that only the last in a chain of descriptors will have FINT
- * sent to signal an interrupt, so that the chain will be completely
- * transmitted by the time we get here, and there's no need to save
- * any of the descriptors.  In particular, use of the DBRI's CDP command
- * is precluded, but I've not been able to get CDP working reliably anyway.
+ * each one's DMA buffer (if present), flagging the descriptor available,
+ * and signaling its callback routine (if present), before proceeding
+ * to the next one.  Stops when the first descriptor is found without
+ * TBC (Transmit Buffer Complete) set, or we've run through them all.
  */
 
 static void transmission_complete_intr(struct dbri *dbri, int pipe)
 {
-        int td = dbri->pipes[pipe].desc;
+       int td;
         int status;
         void *buffer;
         void (*callback)(void *, int);
+       void *callback_arg;
 
-        dbri->pipes[pipe].desc = -1;
+       td = dbri->pipes[pipe].desc;
 
-        for (; td >= 0; td = dbri->descs[td].next) {
+       while (td >= 0) {
 
                 if (td >= DBRI_NO_DESCS) {
                         printk("DBRI: invalid td on pipe %d\n", pipe);
                         return;
                 }
 
-                status = dbri->dma->desc[td].word4;
+               status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);
+
+               if (! (status & DBRI_TD_TBC)) {
+                       break;
+               }
+
+               dprintk(D_INT, ("DBRI: TD %d, status 0x%02x\n", td, status));
 
                 buffer = dbri->descs[td].buffer;
                 if (buffer) {
@@ -313,12 +351,16 @@ static void transmission_complete_intr(struct dbri *dbri, int pipe)
                 }
 
                 callback = dbri->descs[td].output_callback;
-                if (callback != NULL) {
-                        callback(dbri->descs[td].output_callback_arg,
-                                 DBRI_TD_STATUS(status) & 0xe);
-                }
+               callback_arg = dbri->descs[td].output_callback_arg;
 
                 dbri->descs[td].inuse = 0;
+
+               td = dbri->descs[td].next;
+               dbri->pipes[pipe].desc = td;
+
+               if (callback != NULL) {
+                       callback(callback_arg, status & 0xe);
+               }
         }
 }
 
@@ -335,7 +377,7 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
         }
 
         dbri->descs[rd].inuse = 0;
-        dbri->pipes[pipe].desc = -1;
+       dbri->pipes[pipe].desc = dbri->descs[rd].next;
         status = dbri->dma->desc[rd].word1;
 
         buffer = dbri->descs[rd].buffer;
@@ -351,86 +393,147 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
                          DBRI_RD_STATUS(status),
                          DBRI_RD_CNT(status)-2);
         }
+
+       dprintk(D_INT, ("DBRI: Recv RD %d, status 0x%02x, len %d\n",
+                       rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)));
 }
 
-static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
+static void dbri_process_one_interrupt(struct dbri *dbri, int x)
 {
-       struct dbri *dbri = (struct dbri *)opaque;
-       int x;
-       
-       /*
-        * Read it, so the interrupt goes away.
-        */
-       x = dbri->regs->reg1;
+       int val = D_INTR_GETVAL(x);
+       int channel = D_INTR_GETCHAN(x);
+       int command = D_INTR_GETCMD(x);
+       int code = D_INTR_GETCODE(x);
+       int rval = D_INTR_GETRVAL(x);
 
-       if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
-               /*
-                * What should I do here ?
-                */
-               if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
-               if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
-               if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
-               if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
+       if (channel == D_INTR_CMD) {
+               dprintk(D_INT,("DBRI: INTR: Command: %-5s  Value:%d\n",
+                              cmds[command], val));
+       } else {
+               dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
+                              channel, code, rval));
        }
 
-       if (!(x & D_IR))        /* Not for us */
-               return;
+       if (channel == D_INTR_CMD && command == D_WAIT) {
+               dbri->wait_seen ++;
+       }
 
-       x = dbri->dma->intr[dbri->dbri_irqp];
-       while (x != 0) {
-                int val = D_INTR_GETVAL(x);
-                int channel = D_INTR_GETCHAN(x);
+       if (code == D_INTR_SBRI) {
 
-               dbri->dma->intr[dbri->dbri_irqp] = 0;
+               /* SBRI - BRI status change */
 
-               if(D_INTR_GETCHAN(x) == D_INTR_CMD) {
-                       dprintk(D_INT,("DBRI: INTR: Command: %-5s  Value:%d\n",
-                               cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x)));
-               } else {
-                       dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
-                               D_INTR_GETCHAN(x), D_INTR_GETCODE(x),
-                               D_INTR_GETRVAL(x)));
-               }
+               int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
+               dbri->liu_state = liu_states[val & 0x7];
+               if (dbri->liu_callback)
+                       dbri->liu_callback(dbri->liu_callback_arg);
+       }
 
-                if (D_INTR_GETCODE(x) == D_INTR_SBRI) {
+       if (code == D_INTR_BRDY) {
+               reception_complete_intr(dbri, channel);
+       }
 
-                        /* SBRI - BRI status change */
+       if (code == D_INTR_XCMP) {
+               transmission_complete_intr(dbri, channel);
+       }
 
-                        int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
-                        dbri->liu_state = liu_states[val & 0x7];
-                        if (dbri->liu_callback)
-                                dbri->liu_callback(dbri->liu_callback_arg);
-                }
+       if (code == D_INTR_UNDR) {
 
-                if (D_INTR_GETCODE(x) == D_INTR_BRDY) {
-                        reception_complete_intr(dbri, channel);
-                }
+               /* UNDR - Transmission underrun
+                * resend SDP command with clear pipe bit (C) set
+                */
 
-                if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
-                        transmission_complete_intr(dbri, channel);
-                }
+               volatile int *cmd;
+               int pipe = channel;
+               int td = dbri->pipes[pipe].desc;
 
-                if (D_INTR_GETCODE(x) == D_INTR_FXDT) {
+               dbri->dma->desc[td].word4 = 0;
 
-                        /* FXDT - Fixed data change */
+               cmd = dbri_cmdlock(dbri);
+               *(cmd++) = DBRI_CMD(D_SDP, 0,
+                                   dbri->pipes[pipe].sdp
+                                   | D_SDP_P | D_SDP_C | D_SDP_2SAME);
+               *(cmd++) = (int) & dbri->dma_dvma->desc[td];
+               dbri_cmdsend(dbri, cmd);
+       }
 
-                        if (dbri->pipes[D_INTR_GETCHAN(x)].sdp & D_SDP_MSB) {
-                                val = reverse_bytes(val, dbri->pipes[channel].length);
-                        }
+       if (code == D_INTR_FXDT) {
 
-                        if (dbri->pipes[D_INTR_GETCHAN(x)].recv_fixed_ptr) {
-                                * dbri->pipes[channel].recv_fixed_ptr = val;
-                        }
+               /* FXDT - Fixed data change */
+
+               if (dbri->pipes[channel].sdp & D_SDP_MSB) {
+                       val = reverse_bytes(val, dbri->pipes[channel].length);
                 }
 
+               if (dbri->pipes[channel].recv_fixed_ptr) {
+                       * dbri->pipes[channel].recv_fixed_ptr = val;
+               }
+       }
+}
+
+/* dbri_process_interrupt_buffer advances through the DBRI's interrupt
+ * buffer until it finds a zero word (indicating nothing more to do
+ * right now).  Non-zero words require processing and are handed off
+ * to dbri_process_one_interrupt AFTER advancing the pointer.  This
+ * order is important since we might recurse back into this function
+ * and need to make sure the pointer has been advanced first.
+ */
+
+static void dbri_process_interrupt_buffer(struct dbri *dbri)
+{
+       int x;
+
+       while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
+
+               dbri->dma->intr[dbri->dbri_irqp] = 0;
 
                dbri->dbri_irqp++;
                if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
                        dbri->dbri_irqp = 1;
                else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0)
                        dbri->dbri_irqp++;
-               x = dbri->dma->intr[dbri->dbri_irqp];
+
+               dbri_process_one_interrupt(dbri, x);
+       }
+}
+
+static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
+{
+       struct dbri *dbri = (struct dbri *)opaque;
+       int x;
+       
+       /*
+        * Read it, so the interrupt goes away.
+        */
+       x = dbri->regs->reg1;
+
+       dprintk(D_INT, ("DBRI: Interrupt!  (reg1=0x%08x)\n", x));
+
+       if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
+
+               if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
+               if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
+               if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
+               if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
+
+               /* Some of these SBus errors cause the chip's SBus circuitry
+                * to be disabled, so just re-enable and try to keep going.
+                *
+                * The only one I've seen is MRR, which will be triggered
+                * if you let a transmit pipe underrun, then try to CDP it.
+                *
+                * If these things persist, we should probably reset
+                * and re-init the chip.
+                */
+
+               dbri->regs->reg0 &= ~D_D;
        }
+
+#if 0
+       if (!(x & D_IR))        /* Not for us */
+               return;
+#endif
+
+       dbri_process_interrupt_buffer(dbri);
 }
 
 
@@ -438,8 +541,22 @@ static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
 ****************************************************************************
 ************************** DBRI data pipe management ***********************
 ****************************************************************************
+
+While DBRI control functions use the command and interrupt buffers, the
+main data path takes the form of data pipes, which can be short (command
+and interrupt driven), or long (attached to DMA buffers).  These functions
+provide a rudimentary means of setting up and managing the DBRI's pipes,
+but the calling functions have to make sure they respect the pipes' linked
+list ordering, among other things.  The transmit and receive functions
+here interface closely with the transmit and receive interrupt code.
+
 */
 
+static int pipe_active(struct dbri *dbri, int pipe)
+{
+       return (dbri->pipes[pipe].desc != -1);
+}
+
 
 /* reset_pipe(dbri, pipe)
  *
@@ -449,6 +566,7 @@ static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
 static void reset_pipe(struct dbri *dbri, int pipe)
 {
         int sdp;
+       int desc;
         volatile int *cmd;
 
         if (pipe < 0 || pipe > 31) {
@@ -467,6 +585,35 @@ static void reset_pipe(struct dbri *dbri, int pipe)
         *(cmd++) = 0;
         dbri_cmdsend(dbri, cmd);
 
+       desc = dbri->pipes[pipe].desc;
+       while (desc != -1) {
+               void *buffer = dbri->descs[desc].buffer;
+               void (*output_callback) (void *, int)
+                       = dbri->descs[desc].output_callback;
+               void *output_callback_arg
+                       = dbri->descs[desc].output_callback_arg;
+               void (*input_callback) (void *, int, unsigned int)
+                       = dbri->descs[desc].input_callback;
+               void *input_callback_arg
+                       = dbri->descs[desc].input_callback_arg;
+
+               if (buffer) {
+                       mmu_release_scsi_one(sbus_dvma_addr(buffer),
+                                            dbri->descs[desc].len,
+                                            dbri->sdev->my_bus);
+               }
+
+               dbri->descs[desc].inuse = 0;
+               desc = dbri->descs[desc].next;
+
+               if (output_callback) {
+                       output_callback(output_callback_arg, -1);
+               }
+               if (input_callback) {
+                       input_callback(input_callback_arg, -1, 0);
+               }
+       }
+
         dbri->pipes[pipe].desc = -1;
 }
 
@@ -482,140 +629,179 @@ static void setup_pipe(struct dbri *dbri, int pipe, int sdp)
                 /* sdp &= 0xf800; */
         }
 
+       /* If this is a fixed receive pipe, arrange for an interrupt
+        * every time its data changes
+        */
+
+       if (D_SDP_MODE(sdp) == D_SDP_FIXED && ! (sdp & D_SDP_TO_SER)) {
+               sdp |= D_SDP_CHANGE;
+       }
+
         sdp |= D_PIPE(pipe);
         dbri->pipes[pipe].sdp = sdp;
+       dbri->pipes[pipe].desc = -1;
 
         reset_pipe(dbri, pipe);
 }
 
-enum master_or_slave { CHImaster, CHIslave };
-
-static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
-                      int bits_per_frame)
+static void link_time_slot(struct dbri *dbri, int pipe,
+                          enum in_or_out direction, int basepipe,
+                          int length, int cycle)
 {
         volatile int *cmd;
         int val;
+       int prevpipe;
+       int nextpipe;
 
-        cmd = dbri_cmdlock(dbri);
+       if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
+               printk("DBRI: link_time_slot called with illegal pipe number\n");
+               return;
+       }
 
-       /* Set CHI Anchor: Pipe 16 */
+       if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
+               printk("DBRI: link_time_slot called on uninitialized pipe\n");
+               return;
+       }
 
-        val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
-                D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
-       *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-       *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
-       *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
+       /* Deal with CHI special case:
+        * "If transmission on edges 0 or 1 is desired, then cycle n
+        *  (where n = # of bit times per frame...) must be used."
+        *                  - DBRI data sheet, page 11
+        */
 
-        dbri->pipes[16].sdp = 1;
-        dbri->pipes[16].nextpipe = 16;
+       if (basepipe == 16 && direction == PIPEoutput && cycle == 0) {
+               cycle = dbri->chi_bpf;
+       }
 
-        if (master_or_slave == CHIslave) {
-                /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
-                 *
-                 * CHICM  = 0 (slave mode, 8 kHz frame rate)
-                 * IR     = give immediate CHI status interrupt
-                 * EN     = give CHI status interrupt upon change
-                 */
-                *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0)
-                                    | D_CHI_IR | D_CHI_EN);
+       if (basepipe == pipe) {
+               prevpipe = pipe;
+               nextpipe = pipe;
         } else {
-                /* Setup DBRI for CHI Master - generate clock, FS
-                 *
-                 * BPF                         =  bits per 8 kHz frame
-                 * 12.288 MHz / CHICM_divisor  = clock rate
-                 * FD  =  1 - drive CHIFS on rising edge of CHICK
+
+               /* We're not initializing a new linked list (basepipe != pipe),
+                * so run through the linked list and find where this pipe
+                * should be sloted in, based on its cycle.  CHI confuses
+                * things a bit, since it has a single anchor for both its
+                * transmit and receive lists.
                  */
 
-                int clockrate = bits_per_frame * 8;
-                int divisor   = 12288 / clockrate;
+               if (basepipe == 16) {
+                       if (direction == PIPEinput) {
+                               prevpipe = dbri->chi_in_pipe;
+                       } else {
+                               prevpipe = dbri->chi_out_pipe;
+                       }
+               } else {
+                       prevpipe = basepipe;
+               }
+
+               nextpipe = dbri->pipes[prevpipe].nextpipe;
 
-                if (divisor > 255 || divisor * clockrate != 12288) {
-                        printk("DBRI: illegal bits_per_frame in setup_chi\n");
+               while (dbri->pipes[nextpipe].cycle < cycle
+                       && dbri->pipes[nextpipe].nextpipe != basepipe) {
+                       prevpipe = nextpipe;
+                       nextpipe = dbri->pipes[nextpipe].nextpipe;
                 }
+       }
 
-                *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
-                                    | D_CHI_IR | D_CHI_EN
-                                    | D_CHI_BPF(bits_per_frame));
+       if (prevpipe == 16) {
+               if (direction == PIPEinput) {
+                       dbri->chi_in_pipe = pipe;
+               } else {
+                       dbri->chi_out_pipe = pipe;
+               }
+       } else {
+               dbri->pipes[prevpipe].nextpipe = pipe;
         }
 
-        /* CHI Data Mode
-         *
-         * RCE   =  0 - receive on falling edge of CHICK
-         * XCE   =  1 - transmit on rising edge of CHICK
-         * XEN   =  1 - enable transmitter
-         * REN   =  1 - enable receiver
-         */
+       dbri->pipes[pipe].nextpipe = nextpipe;
+       dbri->pipes[pipe].cycle = cycle;
+       dbri->pipes[pipe].length = length;
 
-        *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+       cmd = dbri_cmdlock(dbri);
 
-        *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+       if (direction == PIPEinput) {
+               val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+               *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+               *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+               *(cmd++) = 0;
+       } else {
+               val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+               *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+               *(cmd++) = 0;
+               *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+       }
 
         dbri_cmdsend(dbri, cmd);
 }
 
-enum in_or_out { PIPEinput, PIPEoutput };
+/* I don't use this function, so it's basically untested. */
 
-static void link_time_slot(struct dbri *dbri, int pipe,
-                           enum in_or_out direction, int prevpipe,
-                           int length, int cycle)
+static void unlink_time_slot(struct dbri *dbri, int pipe,
+                            enum in_or_out direction, int prevpipe,
+                            int nextpipe)
 {
         volatile int *cmd;
         int val;
-        int nextpipe;
 
         if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
-                printk("DBRI: link_time_slot called with illegal pipe number\n");
-                return;
-        }
-
-        if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0) {
-                printk("DBRI: link_time_slot called on uninitialized pipe\n");
+               printk("DBRI: unlink_time_slot called with illegal pipe number\n");
                 return;
         }
 
-        if (pipe == prevpipe) {
-                nextpipe = pipe;
-        } else {
-                nextpipe = dbri->pipes[prevpipe].nextpipe;
-        }
-
-        dbri->pipes[pipe].nextpipe = nextpipe;
-        dbri->pipes[pipe].cycle = cycle;
-        dbri->pipes[pipe].length = length;
-
         cmd = dbri_cmdlock(dbri);
 
         if (direction == PIPEinput) {
-                val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+               val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
                 *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-                *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+               *(cmd++) = D_TS_NEXT(nextpipe);
                 *(cmd++) = 0;
         } else {
-                val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+               val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
                 *(cmd++) = DBRI_CMD(D_DTS, 0, val);
                 *(cmd++) = 0;
-                *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+               *(cmd++) = D_TS_NEXT(nextpipe);
         }
 
         dbri_cmdsend(dbri, cmd);
 }
 
+/* xmit_fixed() / recv_fixed()
+ *
+ * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
+ * expected to change much, and which we don't need to buffer.
+ * The DBRI only interrupts us when the data changes (receive pipes),
+ * or only changes the data when this function is called (transmit pipes).
+ * Only short pipes (numbers 16-31) can be used in fixed data mode.
+ *
+ * These function operate on a 32-bit field, no matter how large
+ * the actual time slot is.  The interrupt handler takes care of bit
+ * ordering and alignment.  An 8-bit time slot will always end up
+ * in the low-order 8 bits, filled either MSB-first or LSB-first,
+ * depending on the settings passed to setup_pipe()
+ */
+
 static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
 {
         volatile int *cmd;
 
         if (pipe < 16 || pipe > 31) {
-                printk("DBRI: xmit_fixed called with illegal pipe number\n");
+               printk("DBRI: xmit_fixed: Illegal pipe number\n");
+               return;
+       }
+
+       if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {
+               printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe);
                 return;
         }
 
         if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
-                printk("DBRI: xmit_fixed called on non-fixed pipe\n");
+               printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);
                 return;
         }
 
         if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-                printk("DBRI: xmit_fixed called on receive pipe\n");
+               printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe);
                 return;
         }
 
@@ -633,21 +819,7 @@ static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
         dbri_cmdsend(dbri, cmd);
 }
 
-/* recv_fixed()
- *
- * Receive data on a "fixed" pipe - i.e, one whose contents are not
- * expected to change much, and which we don't need to read constantly
- * into a buffer.  The DBRI only interrupts us when the data changes.
- * Only short pipes (numbers 16-31) can be used in fixed data mode.
- *
- * Pass this function a pointer to a 32-bit field, no matter how large
- * the actual time slot is.  The interrupt handler takes care of bit
- * ordering and alignment.  An 8-bit time slot will always end up
- * in the low-order 8 bits, filled either MSB-first or LSB-first,
- * depending on the settings passed to setup_pipe()
- */
-
-static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
+static void recv_fixed(struct dbri *dbri, int pipe, volatile __u32 *ptr)
 {
         if (pipe < 16 || pipe > 31) {
                 printk("DBRI: recv_fixed called with illegal pipe number\n");
@@ -655,12 +827,12 @@ static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
         }
 
         if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
-                printk("DBRI: recv_fixed called on non-fixed pipe\n");
+               printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe);
                 return;
         }
 
         if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-                printk("DBRI: recv_fixed called on transmit pipe\n");
+               printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe);
                 return;
         }
 
@@ -668,37 +840,46 @@ static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
 }
 
 
+/* xmit_on_pipe() / recv_on_pipe()
+ *
+ * Transmit/receive data on a "long" pipe - i.e, one associated
+ * with a DMA buffer.
+ *
+ * Only pipe numbers 0-15 can be used in this mode.
+ *
+ * Both functions take pointer/len arguments pointing to a data buffer,
+ * and both provide callback functions (may be NULL) to notify higher
+ * level code when transmission/reception is complete.
+ *
+ * Both work by building chains of descriptors which identify the
+ * data buffers.  Buffers too large for a single descriptor will
+ * be spread across multiple descriptors.
+ */
+
 static void xmit_on_pipe(struct dbri *dbri, int pipe,
                          void * buffer, unsigned int len,
                          void (*callback)(void *, int), void * callback_arg)
 {
         volatile int *cmd;
+       register unsigned int flags;
         int td = 0;
         int first_td = -1;
-        int last_td;
+       int last_td = -1;
         __u32 dvma_buffer;
 
         if (pipe < 0 || pipe > 15) {
-                printk("DBRI: xmit_on_pipe called with illegal pipe number\n");
+               printk("DBRI: xmit_on_pipe: Illegal pipe number\n");
                 return;
         }
 
         if (dbri->pipes[pipe].sdp == 0) {
-                printk("DBRI: xmit_on_pipe called on uninitialized pipe\n");
+               printk("DBRI: xmit_on_pipe: Uninitialized pipe %d\n", pipe);
                 return;
         }
 
         if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-                printk("DBRI: xmit_on_pipe called on receive pipe\n");
-                return;
-        }
-
-        /* XXX Fix this XXX
-         * Should be able to queue multiple buffers to send on a pipe
-         */
-
-        if (dbri->pipes[pipe].desc != -1) {
-                printk("DBRI: xmit_on_pipe called on active pipe\n");
+               printk("DBRI: xmit_on_pipe: Called on receive pipe %d\n",
+                      pipe);
                 return;
         }
 
@@ -707,10 +888,11 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
         while (len > 0) {
                 int mylen;
 
-                for (td; td < DBRI_NO_DESCS; td ++) {
+               for (; td < DBRI_NO_DESCS; td ++) {
                         if (! dbri->descs[td].inuse) break;
                 }
                 if (td == DBRI_NO_DESCS) {
+                       printk("DBRI: xmit_on_pipe: No descriptors\n");
                         break;
                 }
 
@@ -744,15 +926,10 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
                 len -= mylen;
         }
 
-        if (first_td == -1) {
-                printk("xmit_on_pipe: No descriptors available\n");
+       if (first_td == -1 || last_td == -1) {
                 return;
         }
 
-        if (len > 0) {
-                printk("xmit_on_pipe: Insufficient descriptors; data truncated\n");
-        }
-
         dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
 
         dbri->descs[last_td].buffer = buffer;
@@ -760,14 +937,54 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
         dbri->descs[last_td].output_callback = callback;
         dbri->descs[last_td].output_callback_arg = callback_arg;
 
-        dbri->pipes[pipe].desc = first_td;
+       for (td=first_td; td != -1; td = dbri->descs[td].next) {
+               dprintk(D_DESC, ("DBRI TD %d: %08x %08x %08x %08x\n",
+                                td,
+                                dbri->dma->desc[td].word1,
+                                dbri->dma->desc[td].ba,
+                                dbri->dma->desc[td].nda,
+                                dbri->dma->desc[td].word4));
+       }
 
-        cmd = dbri_cmdlock(dbri);
+       save_and_cli(flags);
 
-        *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
-        *(cmd++) = (int) & dbri->dma_dvma->desc[first_td];
+       if (pipe_active(dbri, pipe)) {
 
-        dbri_cmdsend(dbri, cmd);
+               /* Pipe is already active - find last TD in use
+                * and link our first TD onto its end.  Then issue
+                * a CDP command to let the DBRI know there's more data.
+                */
+
+               last_td = dbri->pipes[pipe].desc;
+               while (dbri->descs[last_td].next != -1)
+                       last_td = dbri->descs[last_td].next;
+
+               dbri->descs[last_td].next = first_td;
+               dbri->dma->desc[last_td].nda =
+                       (int) & dbri->dma_dvma->desc[first_td];
+
+               cmd = dbri_cmdlock(dbri);
+               *(cmd++) = DBRI_CMD(D_CDP, 0, pipe);
+               dbri_cmdsend(dbri,cmd);
+
+       } else {
+
+               /* Pipe isn't active - issue an SDP command to start
+                * our chain of TDs running.
+                */
+
+               dbri->pipes[pipe].desc = first_td;
+
+               cmd = dbri_cmdlock(dbri);
+               *(cmd++) = DBRI_CMD(D_SDP, 0,
+                                   dbri->pipes[pipe].sdp
+                                   | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+               *(cmd++) = (int) & dbri->dma_dvma->desc[first_td];
+               dbri_cmdsend(dbri, cmd);
+
+       }
+
+       restore_flags(flags);
 }
 
 static void recv_on_pipe(struct dbri *dbri, int pipe,
@@ -776,78 +993,231 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
                          void * callback_arg)
 {
         volatile int *cmd;
+       int first_rd = -1;
+       int last_rd = -1;
         int rd;
+       __u32 bus_buffer;
 
         if (pipe < 0 || pipe > 15) {
-                printk("DBRI: recv_on_pipe called with illegal pipe number\n");
+               printk("DBRI: recv_on_pipe: Illegal pipe number\n");
                 return;
         }
 
         if (dbri->pipes[pipe].sdp == 0) {
-                printk("DBRI: recv_on_pipe called on uninitialized pipe\n");
+               printk("DBRI: recv_on_pipe: Uninitialized pipe %d\n", pipe);
                 return;
         }
 
         if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-                printk("DBRI: recv_on_pipe called on transmit pipe\n");
+               printk("DBRI: recv_on_pipe: Called on transmit pipe %d\n",
+                      pipe);
                 return;
         }
 
         /* XXX Fix this XXX
-         * Should be able to queue multiple buffers to send on a pipe
+        * Should be able to queue multiple buffers to receive on a pipe
          */
 
         if (dbri->pipes[pipe].desc != -1) {
-                printk("DBRI: recv_on_pipe called on active pipe\n");
+               printk("DBRI: recv_on_pipe: Called on active pipe %d\n", pipe);
                 return;
         }
 
-        /* XXX Fix this XXX
-         * Use multiple descriptors, if needed, to fit in all the data
-         */
-
-        if (len > (1 << 13) - 1) {
-                printk("recv_on_pipe called with len=%d; truncated\n", len);
-                len = (1 << 13) - 1;
-        }
-
         /* Make sure buffer size is multiple of four */
         len &= ~3;
 
-        for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
-                if (! dbri->descs[rd].inuse) break;
+       bus_buffer = mmu_get_scsi_one(buffer, len, dbri->sdev->my_bus);
+
+       while (len > 0) {
+               int rd;
+               int mylen;
+
+               if (len > (1 << 13) - 4) {
+                       mylen = (1 << 13) - 4;
+               } else {
+                       mylen = len;
+               }
+
+               for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
+                       if (! dbri->descs[rd].inuse) break;
+               }
+               if (rd == DBRI_NO_DESCS) {
+                       printk("DBRI recv_on_pipe: No descriptors\n");
+                       break;
+               }
+
+               dbri->dma->desc[rd].word1 = 0;
+               dbri->dma->desc[rd].ba = bus_buffer;
+               dbri->dma->desc[rd].nda = 0;
+               dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(mylen);
+
+               dbri->descs[rd].buffer = NULL;
+               dbri->descs[rd].len = 0;
+               dbri->descs[rd].input_callback = NULL;
+               dbri->descs[rd].output_callback = NULL;
+               dbri->descs[rd].next = -1;
+               dbri->descs[rd].inuse = 1;
+
+               if (first_rd == -1) first_rd = rd;
+               if (last_rd != -1) {
+                       dbri->dma->desc[last_rd].nda =
+                               (int) & dbri->dma_dvma->desc[rd];
+                       dbri->descs[last_rd].next = rd;
+               }
+               last_rd = rd;
+
+               bus_buffer += mylen;
+               len -= mylen;
         }
-        if (rd == DBRI_NO_DESCS) {
-                printk("DBRI xmit_on_pipe: No descriptors available\n");
+
+       if (last_rd == -1 || first_rd == -1) {
                 return;
         }
 
-        dbri->dma->desc[rd].word1 = 0;
-        dbri->dma->desc[rd].ba = mmu_get_scsi_one(buffer, len,
-                                                  dbri->sdev->my_bus);
-        dbri->dma->desc[rd].nda = 0;
-        dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(len);
+       for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {
+               dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",
+                                rd,
+                                dbri->dma->desc[rd].word1,
+                                dbri->dma->desc[rd].ba,
+                                dbri->dma->desc[rd].nda,
+                                dbri->dma->desc[rd].word4));
+       }
 
-        dbri->descs[rd].buffer = buffer;
-        dbri->descs[rd].len = len;
-        dbri->descs[rd].input_callback = callback;
-        dbri->descs[rd].input_callback_arg = callback_arg;
+       dbri->descs[last_rd].buffer = buffer;
+       dbri->descs[last_rd].len = len;
+       dbri->descs[last_rd].input_callback = callback;
+       dbri->descs[last_rd].input_callback_arg = callback_arg;
 
-        dbri->pipes[pipe].desc = rd;
+       dbri->pipes[pipe].desc = first_rd;
 
         cmd = dbri_cmdlock(dbri);
 
-        *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P);
-        *(cmd++) = (int) & dbri->dma_dvma->desc[rd];
+       *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
+       *(cmd++) = (int) & dbri->dma_dvma->desc[first_rd];
 
         dbri_cmdsend(dbri, cmd);
 }
 
 
+/*
+****************************************************************************
+************************** DBRI - CHI interface ****************************
+****************************************************************************
+
+The CHI is a four-wire (clock, frame sync, data in, data out) time-division
+multiplexed serial interface which the DBRI can operate in either master
+(give clock/frame sync) or slave (take clock/frame sync) mode.
+
+*/
+
+enum master_or_slave { CHImaster, CHIslave };
+
+static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
+                     int bits_per_frame)
+{
+       volatile int *cmd;
+       int val;
+       static int chi_initialized=0;
+
+       if (!chi_initialized) {
+
+               cmd = dbri_cmdlock(dbri);
+
+               /* Set CHI Anchor: Pipe 16 */
+
+               val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
+               *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+               *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+               *(cmd++) = 0;
+
+               val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
+               *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+               *(cmd++) = 0;
+               *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+
+               dbri->pipes[16].sdp = 1;
+               dbri->pipes[16].nextpipe = 16;
+               dbri->chi_in_pipe = 16;
+               dbri->chi_out_pipe = 16;
+
+#if 0
+               chi_initialized ++;
+#endif
+       } else {
+               int pipe;
+
+               for (pipe = dbri->chi_in_pipe;
+                    pipe != 16;
+                    pipe = dbri->pipes[pipe].nextpipe) {
+                       unlink_time_slot(dbri, pipe, PIPEinput,
+                                        16, dbri->pipes[pipe].nextpipe);
+               }
+               for (pipe = dbri->chi_out_pipe;
+                    pipe != 16;
+                    pipe = dbri->pipes[pipe].nextpipe) {
+                       unlink_time_slot(dbri, pipe, PIPEoutput,
+                                        16, dbri->pipes[pipe].nextpipe);
+               }
+
+               dbri->chi_in_pipe = 16;
+               dbri->chi_out_pipe = 16;
+
+               cmd = dbri_cmdlock(dbri);
+
+       }
+
+       if (master_or_slave == CHIslave) {
+               /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
+                *
+                * CHICM  = 0 (slave mode, 8 kHz frame rate)
+                * IR     = give immediate CHI status interrupt
+                * EN     = give CHI status interrupt upon change
+                */
+               *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
+       } else {
+               /* Setup DBRI for CHI Master - generate clock, FS
+                *
+                * BPF                          =  bits per 8 kHz frame
+                * 12.288 MHz / CHICM_divisor   = clock rate
+                * FD  =  1 - drive CHIFS on rising edge of CHICK
+                */
+
+               int clockrate = bits_per_frame * 8;
+               int divisor   = 12288 / clockrate;
+
+               if (divisor > 255 || divisor * clockrate != 12288) {
+                       printk("DBRI: illegal bits_per_frame in setup_chi\n");
+               }
+
+               *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
+                                   | D_CHI_BPF(bits_per_frame));
+       }
+
+       dbri->chi_bpf = bits_per_frame;
+
+       /* CHI Data Mode
+        *
+        * RCE   =  0 - receive on falling edge of CHICK
+        * XCE   =  1 - transmit on rising edge of CHICK
+        * XEN   =  1 - enable transmitter
+        * REN   =  1 - enable receiver
+        */
+
+       *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+       *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+
+       dbri_cmdsend(dbri, cmd);
+}
+
 /*
 ****************************************************************************
 *********************** CS4215 audio codec management **********************
 ****************************************************************************
+
+In the standard SPARC audio configuration, the CS4215 codec is attached
+to the DBRI via the CHI interface and few of the DBRI's PIO pins.
+
 */
 
 
@@ -872,21 +1242,83 @@ static void mmcodec_default(struct cs4215 *mm)
         * 2: Serial enable, CHI master, 128 bits per frame, clock 1
         * 3: Tests disabled
         */
-       mm->ctrl[0] = CS4215_RSRVD_1;
+       mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;
        mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
        mm->ctrl[2] = CS4215_XCLK |
                        CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
        mm->ctrl[3] = 0;
 }
 
+static void mmcodec_setup_pipes(struct dbri *dbri)
+{
+       /*
+        * Data mode:
+        * Pipe  4: Send timeslots 1-4 (audio data)
+        * Pipe 20: Send timeslots 5-8 (part of ctrl data)
+        * Pipe  6: Receive timeslots 1-4 (audio data)
+        * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
+        *          interrupt, and the rest of the data (slot 5 and 8) is
+        *          not relevant for us (only for doublechecking).
+        *
+        * Control mode:
+        * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
+        * Pipe 18: Receive timeslot 1 (clb).
+        * Pipe 19: Receive timeslot 7 (version). 
+        */
+
+       setup_pipe(dbri,  4, D_SDP_MEM   | D_SDP_TO_SER | D_SDP_MSB);
+       setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+       setup_pipe(dbri,  6, D_SDP_MEM   | D_SDP_FROM_SER | D_SDP_MSB);
+       setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+
+       setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER   | D_SDP_MSB);
+       setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+       setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+
+       dbri->mm.status = 0;
+
+       recv_fixed(dbri, 18, & dbri->mm.status);
+       recv_fixed(dbri, 19, & dbri->mm.version);
+}
+
+static void mmcodec_setgain(struct dbri *dbri, int muted)
+{
+       if (muted || dbri->perchip_info.output_muted) {
+               dbri->mm.data[0] = 63;
+               dbri->mm.data[1] = 63;
+       } else {
+               int left_gain = (dbri->perchip_info.play.gain / 4) % 64;
+               int right_gain = (dbri->perchip_info.play.gain / 4) % 64;
+
+               if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) {
+                       right_gain *= dbri->perchip_info.play.balance;
+                       right_gain /= AUDIO_MID_BALANCE;
+               } else {
+                       left_gain *= AUDIO_RIGHT_BALANCE
+                               - dbri->perchip_info.play.balance;
+                       left_gain /= AUDIO_MID_BALANCE;
+               }
+
+               dprintk(D_MM, ("DBRI: Setting codec gain left: %d right: %d\n",
+                              left_gain, right_gain));
+
+               dbri->mm.data[0] = CS4215_LE | CS4215_HE | (63 - left_gain);
+               dbri->mm.data[1] = CS4215_SE | (63 - right_gain);
+       }
+
+       xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
+}
+
 static void mmcodec_init_data(struct dbri *dbri)
 {
+       int data_width;
+
        /*
         * Data mode:
         * Pipe  4: Send timeslots 1-4 (audio data)
-        * Pipe 17: Send timeslots 5-8 (part of ctrl data)
+        * Pipe 20: Send timeslots 5-8 (part of ctrl data)
         * Pipe  6: Receive timeslots 1-4 (audio data)
-        * Pipe 20: Receive timeslots 6-7. We can only receive 20 bits via
+        * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
         *          interrupt, and the rest of the data (slot 5 and 8) is
         *          not relevant for us (only for doublechecking).
          *
@@ -896,35 +1328,55 @@ static void mmcodec_init_data(struct dbri *dbri)
         */
 
 
+       dbri->regs->reg0 &= ~D_C;       /* Disable CHI */
+
         /* Switch CS4215 to data mode - set PIO3 to 1 */
        dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
                                (dbri->mm.onboard ? D_PIO0 : D_PIO2);
 
-       reset_chi(dbri, CHIslave, 0);
+       reset_chi(dbri, CHIslave, 128);
+
+       /* Note: this next doesn't work for 8-bit stereo, because the two
+        * channels would be on timeslots 1 and 3, with 2 and 4 idle.
+        * (See CS4215 datasheet Fig 15)
+        *
+        * DBRI non-contiguous mode would be required to make this work.
+        */
 
-        setup_pipe(dbri,  4, D_SDP_MEM   | D_SDP_TO_SER | D_SDP_MSB);
-        setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
-        setup_pipe(dbri,  6, D_SDP_MEM   | D_SDP_FROM_SER | D_SDP_MSB);
-        setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+       data_width = dbri->perchip_info.play.channels
+               * dbri->perchip_info.play.precision;
 
-        /* Pipes 4 and 6 - Single time slot, 8 bit mono */
+       link_time_slot(dbri, 20, PIPEoutput, 16,
+                      32, dbri->mm.offset + 32);
+       link_time_slot(dbri,  4, PIPEoutput, 16,
+                      data_width, dbri->mm.offset);
+       link_time_slot(dbri,  6, PIPEinput, 16,
+                      data_width, dbri->mm.offset);
+       link_time_slot(dbri, 21, PIPEinput, 16,
+                      16, dbri->mm.offset + 40);
 
-        link_time_slot(dbri, 17, PIPEoutput, 16, 32, 32);
-        link_time_slot(dbri,  4, PIPEoutput, 17, 8, 128);
-        link_time_slot(dbri,  6, PIPEinput, 16, 8, 0);
-        link_time_slot(dbri, 20, PIPEinput, 6, 16, 40);
+       mmcodec_setgain(dbri, 0);
 
-        xmit_fixed(dbri, 17, *(int *)dbri->mm.data);
+       dbri->regs->reg0 |= D_C;        /* Enable CHI */
 }
 
 
 /*
  * Send the control information (i.e. audio format)
  */
-static void mmcodec_setctrl(struct dbri *dbri)
+static int mmcodec_setctrl(struct dbri *dbri)
 {
        int i, val;
 
+       /* XXX - let the CPU do something useful during these delays */
+
+       /* Temporarily mute outputs, and wait 1/8000 sec (125 us)
+        * to make sure this takes.  This avoids clicking noises.
+        */
+
+       mmcodec_setgain(dbri, 1);
+       udelay(125);
+
        /*
         * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
         * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
@@ -952,6 +1404,8 @@ static void mmcodec_setctrl(struct dbri *dbri)
          * frame sync signal by eight clock cycles.  Anybody know why?
          */
 
+       dbri->regs->reg0 &= ~D_C;       /* Disable CHI */
+
         reset_chi(dbri, CHImaster, 128);
 
        /*
@@ -961,27 +1415,26 @@ static void mmcodec_setctrl(struct dbri *dbri)
         * Pipe 19: Receive timeslot 7 (version). 
         */
 
-        setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
-        setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
-        setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
-
-        link_time_slot(dbri, 17, PIPEoutput, 16, 32, 128);
-        link_time_slot(dbri, 18, PIPEinput, 16, 8, 0);
-        link_time_slot(dbri, 19, PIPEinput, 18, 8, 48);
-
-        recv_fixed(dbri, 18, & dbri->mm.status);
-        recv_fixed(dbri, 19, & dbri->mm.version);
+       link_time_slot(dbri, 17, PIPEoutput, 16,
+                      32, dbri->mm.offset);
+       link_time_slot(dbri, 18, PIPEinput, 16,
+                      8, dbri->mm.offset);
+       link_time_slot(dbri, 19, PIPEinput, 16,
+                      8, dbri->mm.offset + 48);
 
         /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
 
        dbri->mm.ctrl[0] &= ~CS4215_CLB;
         xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
 
-        i = 1000000;
-        while ((! dbri->mm.status & CS4215_CLB) && i--);
+       dbri->regs->reg0 |= D_C;        /* Enable CHI */
+
+       i = 10;
+       while (((dbri->mm.status & 0xe4) != 0x20) && --i) udelay(125);
         if (i == 0) {
-                printk("CS4215 didn't respond to CLB\n");
-               return;
+               dprintk(D_MM, ("DBRI: CS4215 didn't respond to CLB (0x%02x)\n",
+                              dbri->mm.status));
+               return -1;
         }
 
         /* Terminate CS4215 control mode - data sheet says
@@ -993,6 +1446,10 @@ static void mmcodec_setctrl(struct dbri *dbri)
 
         /* Two frames of control info @ 8kHz frame rate = 250 us delay */
         udelay(250);
+
+       mmcodec_setgain(dbri, 0);
+
+       return 0;
 }
 
 static int mmcodec_init(struct sparcaudio_driver *drv)
@@ -1024,16 +1481,24 @@ static int mmcodec_init(struct sparcaudio_driver *drv)
        }
 
 
-       /* Now talk to our baby */
-       dbri->regs->reg0 |= D_C;        /* Enable CHI */
+       mmcodec_setup_pipes(dbri);
 
        mmcodec_default(&dbri->mm);
 
        dbri->mm.version = 0xff;
-       mmcodec_setctrl(dbri);
-       if(dbri->mm.version == 0xff) 
+       dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
+       if (mmcodec_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
+               dprintk(D_MM, ("DBRI: CS4215 failed probe at offset %d\n",
+                              dbri->mm.offset));
                return -EIO;
+       }
 
+       dprintk(D_MM, ("DBRI: Found CS4215 at offset %d\n", dbri->mm.offset));
+
+       dbri->perchip_info.play.channels = 1;
+       dbri->perchip_info.play.precision = 8;
+       dbri->perchip_info.play.gain = 255;
+       dbri->perchip_info.play.balance = AUDIO_MID_BALANCE;
        mmcodec_init_data(dbri);
 
        return 0;
@@ -1044,37 +1509,25 @@ static int mmcodec_init(struct sparcaudio_driver *drv)
 ****************************************************************************
 ******************** Interface with sparcaudio midlevel ********************
 ****************************************************************************
-*/
 
+The sparcaudio midlevel is contained in the file audio.c.  It interfaces
+to the user process and performs buffering, intercepts SunOS-style ioctl's,
+etc.  It interfaces to a abstract audio device via a struct sparcaudio_driver.
+This code presents such an interface for the DBRI with an attached CS4215.
+All our routines are defined, and then comes our struct sparcaudio_driver.
 
-static int dbri_open(struct inode * inode, struct file * file,
-                     struct sparcaudio_driver *drv)
-{
-       struct dbri *dbri = (struct dbri *)drv->private;
-
-       MOD_INC_USE_COUNT;
+*/
 
-       return 0;
-}
+/******************* sparcaudio midlevel - audio output *******************/
 
-static void dbri_release(struct inode * inode, struct file * file,
-                         struct sparcaudio_driver *drv)
-{
-       MOD_DEC_USE_COUNT;
-}
-
-static int dbri_ioctl(struct inode * inode, struct file * file,
-                      unsigned int x, unsigned long y,
-                      struct sparcaudio_driver *drv)
-{
-        return 0;
-}
 
 static void dbri_audio_output_callback(void * callback_arg, int status)
 {
         struct sparcaudio_driver *drv = callback_arg;
 
-        sparcaudio_output_done(drv, 1);
+       if (status != -1) {
+               sparcaudio_output_done(drv, 1);
+       }
 }
 
 static void dbri_start_output(struct sparcaudio_driver *drv,
@@ -1082,8 +1535,31 @@ static void dbri_start_output(struct sparcaudio_driver *drv,
 {
        struct dbri *dbri = (struct dbri *)drv->private;
 
+       dprintk(D_USR, ("DBRI: start audio output buf=%lx/%ld\n",
+                       (unsigned long) buffer, count));
+
         /* Pipe 4 is audio transmit */
-        xmit_on_pipe(dbri, 4, buffer, count, &dbri_audio_output_callback, drv);
+
+       xmit_on_pipe(dbri, 4, buffer, count,
+                    &dbri_audio_output_callback, drv);
+
+#if 0
+       /* Notify midlevel that we're a DMA-capable driver that
+        * can accept another buffer immediately.  We should probably
+        * check that we've got enough resources (i.e, descriptors)
+        * available before doing this, but the default midlevel
+        * settings only buffer 64KB, which we can handle with 16
+        * of our DBRI_NO_DESCS (64) descriptors.
+        *
+        * This code is #ifdef'ed out because it's caused me more
+        * problems than it solved.  It'd be nice to provide the
+        * DBRI with a chain of buffers, but the midlevel code is
+        * so tricky that I really don't want to deal with it.
+        */
+
+       sparcaudio_output_done(drv, 2);
+#endif
+
 }
 
 static void dbri_stop_output(struct sparcaudio_driver *drv)
@@ -1093,28 +1569,55 @@ static void dbri_stop_output(struct sparcaudio_driver *drv)
         reset_pipe(dbri, 4);
 }
 
+/******************* sparcaudio midlevel - audio input ********************/
+
+static void dbri_audio_input_callback(void * callback_arg, int status,
+                                     unsigned int len)
+{
+       struct sparcaudio_driver * drv =
+               (struct sparcaudio_driver *) callback_arg;
+
+       if (status != -1) {
+               sparcaudio_input_done(drv, 3);
+       }
+}
+
 static void dbri_start_input(struct sparcaudio_driver *drv,
                              __u8 * buffer, unsigned long len)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       /* Pipe 6 is audio receive */
+       recv_on_pipe(dbri, 6, buffer, len,
+                    &dbri_audio_input_callback, (void *)drv);
+       dprintk(D_USR, ("DBRI: start audio input buf=%lx/%ld\n",
+                       (unsigned long) buffer, len));
 }
 
 static void dbri_stop_input(struct sparcaudio_driver *drv)
 {
-}
+       struct dbri *dbri = (struct dbri *)drv->private;
 
-static void dbri_audio_getdev(struct sparcaudio_driver *drv,
-                              audio_device_t *devptr)
-{
+       reset_pipe(dbri, 6);
 }
 
+/******************* sparcaudio midlevel - volume & balance ***************/
+
 static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       dbri->perchip_info.play.gain = volume;
+       mmcodec_setgain(dbri, 0);
+
         return 0;
 }
 
 static int dbri_get_output_volume(struct sparcaudio_driver *drv)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.gain;
 }
 
 static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume)
@@ -1139,12 +1642,19 @@ static int dbri_get_monitor_volume(struct sparcaudio_driver *drv)
 
 static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       dbri->perchip_info.play.balance = balance;
+       mmcodec_setgain(dbri, 0);
+
         return 0;
 }
 
 static int dbri_get_output_balance(struct sparcaudio_driver *drv)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.balance;
 }
 
 static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance)
@@ -1157,107 +1667,205 @@ static int dbri_get_input_balance(struct sparcaudio_driver *drv)
         return 0;
 }
 
+static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
+{
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       dbri->perchip_info.output_muted = mute;
+
+       return 0;
+}
+
+static int dbri_get_output_muted(struct sparcaudio_driver *drv)
+{
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.output_muted;
+}
+
+/******************* sparcaudio midlevel - encoding format ****************/
+
 static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       switch (chan) {
+       case 0:
+               return 0;
+       case 1:
+               dbri->mm.ctrl[1] &= ~CS4215_DFR_STEREO;
+               break;
+       case 2:
+               dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
+               break;
+       default:
+               return -1;
+       }
+
+       dbri->perchip_info.play.channels = chan;
+       mmcodec_setctrl(dbri);
+       mmcodec_init_data(dbri);
         return 0;
 }
 
 static int dbri_get_output_channels(struct sparcaudio_driver *drv)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.channels;
 }
 
 static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan)
 {
-        return 0;
+       return dbri_set_output_channels(drv, chan);
 }
 
 static int dbri_get_input_channels(struct sparcaudio_driver *drv)
 {
-        return 0;
+       return dbri_get_output_channels(drv);
 }
 
 static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec)
 {
-        return 8;
+       return 0;
 }
 
 static int dbri_get_output_precision(struct sparcaudio_driver *drv)
 {
-        return 8;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.precision;
 }
 
 static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec)
 {
-        return 8;
+       return 0;
 }
 
 static int dbri_get_input_precision(struct sparcaudio_driver *drv)
 {
-        return 8;
-}
+       struct dbri *dbri = (struct dbri *)drv->private;
 
-static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
-{
-        return 0;
+       return dbri->perchip_info.play.precision;
 }
 
-static int dbri_get_output_port(struct sparcaudio_driver *drv)
+static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       /* For ULAW and ALAW, audio.c enforces precision = 8,
+        * for LINEAR, precision must be 16
+        */
+
+       switch (enc) {
+       case AUDIO_ENCODING_NONE:
+               return 0;
+       case AUDIO_ENCODING_ULAW:
+               dbri->mm.ctrl[1] &= ~3;
+               dbri->mm.ctrl[1] |= CS4215_DFR_ULAW;
+               dbri->perchip_info.play.encoding = enc;
+               dbri->perchip_info.play.precision = 8;
+               break;
+       case AUDIO_ENCODING_ALAW:
+               dbri->mm.ctrl[1] &= ~3;
+               dbri->mm.ctrl[1] |= CS4215_DFR_ALAW;
+               dbri->perchip_info.play.encoding = enc;
+               dbri->perchip_info.play.precision = 8;
+               break;
+       case AUDIO_ENCODING_LINEAR:
+               dbri->mm.ctrl[1] &= ~3;
+               dbri->mm.ctrl[1] |= CS4215_DFR_LINEAR16;
+               dbri->perchip_info.play.encoding = enc;
+               dbri->perchip_info.play.precision = 16;
+               break;
+       default:
+               return -1;
+       }
+       mmcodec_setctrl(dbri);
+       mmcodec_init_data(dbri);
         return 0;
 }
 
-static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
+static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.encoding;
 }
 
-static int dbri_get_input_port(struct sparcaudio_driver *drv)
+static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
 {
-        return 0;
+       return dbri_set_output_encoding(drv, enc);
 }
 
-static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
+static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
 {
-        return 0;
+       return dbri_get_output_encoding(drv);
 }
 
-static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
+static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
 {
+       struct dbri *dbri = (struct dbri *)drv->private;
+       int i;
+
+       if (rate == 0) {
+               return 0;
+       }
+
+       for (i=0; CS4215_FREQ[i].freq; i++) {
+               if (CS4215_FREQ[i].freq == rate) break;
+       }
+       if (CS4215_FREQ[i].freq == 0) {
+               return -1;
+       }
+
+       dbri->mm.ctrl[1] &= ~ 0x38;
+       dbri->mm.ctrl[1] |= CS4215_FREQ[i].csval;
+       dbri->mm.ctrl[2] &= ~ 0x70;
+       dbri->mm.ctrl[2] |= CS4215_FREQ[i].xtal;
+
+       dbri->perchip_info.play.sample_rate = rate;
+
+       mmcodec_setctrl(dbri);
+       mmcodec_init_data(dbri);
         return 0;
 }
 
-static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
+static int dbri_get_output_rate(struct sparcaudio_driver *drv)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       return dbri->perchip_info.play.sample_rate;
 }
 
-static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
+static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
 {
-        return 0;
+       return dbri_set_output_rate(drv, rate);
 }
 
-static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
+static int dbri_get_input_rate(struct sparcaudio_driver *drv)
 {
-        return 0;
+       return dbri_get_output_rate(drv);
 }
 
-static int dbri_get_output_rate(struct sparcaudio_driver *drv)
+/******************* sparcaudio midlevel - ports ***********************/
+
+static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
 {
         return 0;
 }
 
-static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
+static int dbri_get_output_port(struct sparcaudio_driver *drv)
 {
         return 0;
 }
 
-static int dbri_get_input_rate(struct sparcaudio_driver *drv)
+static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
 {
         return 0;
 }
 
-static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
+static int dbri_get_input_port(struct sparcaudio_driver *drv)
 {
         return 0;
 }
@@ -1272,17 +1880,66 @@ static int dbri_get_input_ports(struct sparcaudio_driver *drv)
         return 0;
 }
 
-static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
+/******************* sparcaudio midlevel - driver ID ********************/
+
+static void dbri_audio_getdev(struct sparcaudio_driver *drv,
+                             audio_device_t *audinfo)
 {
-        return 0;
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+       strncpy(audinfo->name, "SUNW,DBRI", sizeof(audinfo->name) - 1);
+
+       audinfo->version[0] = dbri->dbri_version;
+       audinfo->version[1] = '\0';
+
+       strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
 }
 
-static int dbri_get_output_muted(struct sparcaudio_driver *drv)
+static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
 {
-        return 0;
+       return AUDIO_DEV_CODEC;
+}
+
+/******************* sparcaudio midlevel - open & close ******************/
+
+static int dbri_open(struct inode * inode, struct file * file,
+                    struct sparcaudio_driver *drv)
+{
+       MOD_INC_USE_COUNT;
+
+       /* SunOS 5.5.1 audio(7I) man page says:
+        * "Upon the initial open() of the audio device, the driver
+        *  will reset the data format of the device to the default
+        *  state of 8-bit, 8KHz, mono u-law data."
+        *
+        * I've also taken the liberty of setting half gain and
+        * mid balance, to put the codec in a known state.
+        */
+
+       dbri_set_output_channels(drv, 1);
+       dbri_set_output_encoding(drv, AUDIO_ENCODING_ULAW);
+       dbri_set_output_rate(drv, 8000);
+
+       dbri_set_output_balance(drv, AUDIO_MID_BALANCE);
+       dbri_set_output_volume(drv, AUDIO_MAX_GAIN/2);
+
+       return 0;
 }
 
+static void dbri_release(struct inode * inode, struct file * file,
+                        struct sparcaudio_driver *drv)
+{
+       MOD_DEC_USE_COUNT;
+}
 
+static int dbri_ioctl(struct inode * inode, struct file * file,
+                     unsigned int x, unsigned long y,
+                     struct sparcaudio_driver *drv)
+{
+       return -EINVAL;
+}
+
+/*********** sparcaudio midlevel - struct sparcaudio_driver ************/
 
 static struct sparcaudio_operations dbri_ops = {
        dbri_open,
@@ -1357,8 +2014,8 @@ void dbri_isdn_init(struct dbri *dbri)
         setup_pipe(dbri,11, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
 
         link_time_slot(dbri, 0, PIPEinput, 0, 2, 17);
-        link_time_slot(dbri, 8, PIPEinput, 8, 8, 0);
-        link_time_slot(dbri, 9, PIPEinput, 9, 8, 8);
+       link_time_slot(dbri, 8, PIPEinput, 0, 8, 0);
+       link_time_slot(dbri, 9, PIPEinput, 8, 8, 8);
 
         link_time_slot(dbri,  1, PIPEoutput,  1, 2, 17);
         link_time_slot(dbri, 10, PIPEoutput,  1, 8, 0);
@@ -1375,6 +2032,8 @@ int dbri_get_irqnum(int dev)
 
        dbri = (struct dbri *) drivers[dev].private;
 
+       tprintk(("dbri_get_irqnum()\n"));
+
         /* On the sparc, the cpu's irq number is only part of the "irq" */
        return (dbri->irq & NR_IRQS);
 }
@@ -1389,6 +2048,8 @@ int dbri_get_liu_state(int dev)
 
        dbri = (struct dbri *) drivers[dev].private;
 
+       tprintk(("dbri_get_liu_state() returns %d\n", dbri->liu_state));
+
        return dbri->liu_state;
 }
 
@@ -1404,12 +2065,14 @@ void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg)
 
        dbri = (struct dbri *) drivers[dev].private;
 
+       tprintk(("dbri_liu_init()\n"));
+
        /* Set callback for LIU state change */
-        dbri->liu_callback = callback;
+       dbri->liu_callback = callback;
        dbri->liu_callback_arg = callback_arg;
 
-        dbri_isdn_init(dbri);
-        dbri_liu_activate(dev, 0);
+       dbri_isdn_init(dbri);
+       dbri_liu_activate(dev, 0);
 }
 
 void dbri_liu_activate(int dev, int priority)
@@ -1424,16 +2087,24 @@ void dbri_liu_activate(int dev, int priority)
 
        dbri = (struct dbri *) drivers[dev].private;
 
-        cmd = dbri_cmdlock(dbri);
+       tprintk(("dbri_liu_activate()\n"));
 
-        /* Turn on the ISDN TE interface and request activation */
-        val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
-        *(cmd++) = DBRI_CMD(D_TE, 0, val);
+       if (dbri->liu_state <= 3) {
 
-       dbri_cmdsend(dbri, cmd);
+              cmd = dbri_cmdlock(dbri);
+
+              /* Turn on the ISDN TE interface and request activation */
+              val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
+#ifdef LOOPBACK_D
+              val |= D_NT_LLB(4);
+#endif
+              *(cmd++) = DBRI_CMD(D_TE, 0, val);
 
-        /* Activate the interface */
-        dbri->regs->reg0 |= D_T;
+              dbri_cmdsend(dbri, cmd);
+
+              /* Activate the interface */
+              dbri->regs->reg0 |= D_T;
+       }
 }
 
 void dbri_liu_deactivate(int dev)
@@ -1446,8 +2117,14 @@ void dbri_liu_deactivate(int dev)
 
        dbri = (struct dbri *) drivers[dev].private;
 
+       tprintk(("dbri_liu_deactivate()\n"));
+
+#if 0
         /* Turn off the ISDN TE interface */
         dbri->regs->reg0 &= ~D_T;
+
+       dbri->liu_state = 0;
+#endif
 }
 
 void dbri_dxmit(int dev, __u8 *buffer, unsigned int count,
@@ -1613,6 +2290,11 @@ static int dbri_attach(struct sparcaudio_driver *drv,
                                        "DBRI DMA Cmd Block", &dma_dvma);
         dbri->dma_dvma = (struct dbri_dma *) dma_dvma;
 
+       memset((void *) dbri->dma, 0, sizeof(struct dbri_dma));
+
+       dprintk(D_GEN, ("DBRI: DMA Cmd Block 0x%08x (0x%08x)\n",
+                       (int)dbri->dma, (int)dbri->dma_dvma));
+
        dbri->dbri_version = sdev->prom_name[9];
         dbri->sdev = sdev;
 
@@ -1625,6 +2307,8 @@ static int dbri_attach(struct sparcaudio_driver *drv,
                "DBRI Registers", sdev->reg_addrs[0].which_io, 0);
        if (!dbri->regs) {
                printk(KERN_ERR "DBRI: could not allocate registers\n");
+               release_region((unsigned long) dbri->dma,
+                              sizeof(struct dbri_dma));
                kfree(drv->private);
                return -EIO;
        }
@@ -1637,6 +2321,8 @@ static int dbri_attach(struct sparcaudio_driver *drv,
        if (err) {
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
                sparc_free_io(dbri->regs, dbri->regs_size);
+               release_region((unsigned long) dbri->dma,
+                              sizeof(struct dbri_dma));
                kfree(drv->private);
                return err;
        }
index 1cd5987438d87ce7454778d26ebac08ea7d7f7be..7b29bf5333f6c33cf7ecdddefcd1510a9551a526 100644 (file)
@@ -46,13 +46,19 @@ struct dbri_dma {
   struct dbri_mem desc[DBRI_NO_DESCS];         /* Xmit/receive descriptors */
 };
 
+enum in_or_out { PIPEinput, PIPEoutput };
+
+enum direction { in, out };
+
 struct dbri_pipe {
         u32 sdp;                               /* SDP command word */
+       enum direction direction;
         int nextpipe;                          /* Next pipe in linked list */
+       int prevpipe;
         int cycle;                             /* Offset of timeslot (bits) */
         int length;                            /* Length of timeslot (bits) */
         int desc;                              /* Index of active descriptor*/
-        __u32 *recv_fixed_ptr;                 /* Ptr to receive fixed data */
+       volatile __u32 *recv_fixed_ptr;         /* Ptr to receive fixed data */
 };
 
 struct dbri_desc {
@@ -78,10 +84,15 @@ struct dbri {
   struct dbri_regs *regs;                      /* dbri HW regs */
   int dbri_version;                            /* 'e' and up is OK */
   int dbri_irqp;                               /* intr queue pointer */
+  int wait_seen;
 
   struct dbri_pipe pipes[32];                  /* DBRI's 32 data pipes */
   struct dbri_desc descs[DBRI_NO_DESCS];
 
+  int chi_in_pipe;
+  int chi_out_pipe;
+  int chi_bpf;
+
   struct cs4215 mm;                            /* mmcodec special info */
 
 #if 0
@@ -190,7 +201,7 @@ struct dbri {
 /* Time Slot defines */
 #define D_TS_LEN(v)    ((v)<<24)       /* Number of bits in this time slot */
 #define D_TS_CYCLE(v)  ((v)<<14)       /* Bit Count at start of TS */
-#define D_TS_DI(v)     (1<<13) /* Data Invert */
+#define D_TS_DI                (1<<13) /* Data Invert */
 #define D_TS_1CHANNEL  (0<<10) /* Single Channel / Normal mode */
 #define D_TS_MONITOR   (2<<10) /* Monitor pipe */
 #define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */
@@ -218,8 +229,8 @@ struct dbri {
 #define D_NT_IFA       (1<<10) /* Inhibit Final Activation */
 #define D_NT_ACT       (1<<9)  /* Activate Interface */
 #define D_NT_MFE       (1<<8)  /* Multiframe Enable */
-#define D_NT_RLB(v)    (1<<5)  /* Remote Loopback */
-#define D_NT_LLB(v)    (1<<2)  /* Local Loopback */
+#define D_NT_RLB(v)    ((v)<<5)        /* Remote Loopback */
+#define D_NT_LLB(v)    ((v)<<2)        /* Local Loopback */
 #define D_NT_FACT      (1<<1)  /* Force Activation */
 #define D_NT_ABV       (1<<0)  /* Activate Bipolar Violation */
 
index a79dc6b6f6bdc964ba1721caccd036cbd855303c..b80b93e92f1735ef11a9bf173833269fe9c741e9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.20 1999/06/03 15:02:40 davem Exp $
+/* $Id: su.c,v 1.21 1999/06/11 10:23:42 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1133,9 +1133,9 @@ static void su_put_char_kbd(unsigned char c)
        struct su_struct *info = su_table;
        int lsr;
 
-       if (!info->port_type != SU_PORT_KBD)
+       if (info->port_type != SU_PORT_KBD)
                ++info;
-       if (!info->port_type != SU_PORT_KBD)
+       if (info->port_type != SU_PORT_KBD)
                return;
 
        do {
@@ -1151,9 +1151,9 @@ su_change_mouse_baud(int baud)
 {
        struct su_struct *info = su_table;
 
-       if (!info->port_type != SU_PORT_MS)
+       if (info->port_type != SU_PORT_MS)
                ++info;
-       if (!info->port_type != SU_PORT_MS)
+       if (info->port_type != SU_PORT_MS)
                return;
 
        info->cflag &= ~(CBAUDEX | CBAUD);
@@ -2215,7 +2215,7 @@ done:
  */
 __initfunc(static __inline__ void show_su_version(void))
 {
-       char *revision = "$Revision: 1.20 $";
+       char *revision = "$Revision: 1.21 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
index 2a6ad294919f34b8590d72ac4d31c3fd1dd6a87a..6388b2e8e1ea9a8bb463586f9dec1598682b1d82 100644 (file)
@@ -67,7 +67,7 @@
    orl %%ecx, %%ecx       \n \
    jz 1f                  \n \
    rep                    \n \
-   insw %%dx              \n \
+   insw (%%dx),%%es:(%%edi) \n \
 1: "                       \
    : "=D" (sp)                   /* output */   \
    : "d" (f), "D" (sp), "c" (i)  /* input */    \
@@ -79,7 +79,7 @@
    orl %%ecx, %%ecx       \n \
    jz 1f                  \n \
    rep                    \n \
-   outsw %%dx             \n \
+   outsw %%ds:(%%esi),(%%dx) \n \
 1: "                       \
    : "=S" (sp)                   /* output */   \
    : "d" (f), "S" (sp), "c" (i)  /* input */    \
index 36a4eafb1c42548e934d662fc0d5459cfcc192f7..04fcd34134e8aa7a6e7b06813ae1332af388e97a 100644 (file)
@@ -24,7 +24,7 @@ void vidc_update_filler(int format, int channels)
 #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
 
        fillertype = TYPE(format, channels);
-printk("filler type: %X\n", fillertype);
+
        switch (fillertype)
        {
                default:
@@ -61,10 +61,13 @@ void attach_vidc(struct address_info *hw_config)
 
        sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
        conf_printf(name, hw_config);
+       memset(dma_buf, 0, sizeof(dma_buf));
 
        for (i = 0; i < 2; i++)
        {
                dma_buf[i] = get_free_page(GFP_KERNEL);
+               if (!dma_buf[i])
+                       goto nomem;
                dma_pbuf[i] = virt_to_phys(dma_buf[i]);
        }
 
@@ -78,9 +81,16 @@ void attach_vidc(struct address_info *hw_config)
                printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n");
                return;
        }
+
 //     vidc_synth_init(hw_config);
        vidc_audio_init(hw_config);
        vidc_mixer_init(hw_config);
+       return;
+
+nomem:
+       for (i = 0; i < 2; i++)
+               free_page(dma_buf[i]);
+       printk(KERN_ERR "VIDCsound: can't allocate required buffers\n");
 }
 
 int probe_vidc(struct address_info *hw_config)
index 7aa2750847eb710ee9ecced0c58cdd0dc4b555ff..3a1f162fb0cca308d1b24001b7c37b3a06850a92 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/iomd.h>
 
 #include "sound_config.h"
 #include "vidc.h"
@@ -42,7 +43,6 @@ int vidc_audio_set_volume(int newvol)
 
 static int vidc_audio_set_bits(int fmt)
 {
-printk("setting format: %d\n", fmt);
        switch (fmt)
        {
                case AFMT_QUERY:
@@ -219,10 +219,11 @@ static void vidc_audio_output_block(int dev, unsigned long buf, int total_count,
        if (!(adev->flags & DMA_ACTIVE))
        {
                unsigned long flags;
-printk("kicking output: %lX+%lX [%lX]\n", dma_start, dma_count, *(unsigned long *)dma_start);
                save_flags_cli(flags);
+
                vidc_sound_dma_irq(0, NULL, NULL);
                outb(DMA_CR_E | 0x10, IOMD_SD0CR);
+
                restore_flags(flags);
        }
 }
index b8b1e6620e7ab5a4cff02ca964f565694c19e7b7..53fc2ed017189dde1c95e92f1b4ac529116c64c5 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
+#include <asm/iomd.h>
 
                .text
 
index 5a707a4b7ec5a3d6cea5b113a883f8239c323625..85a9efaec91ac43223414ef860f50c85c257dd08 100644 (file)
 #include <linux/delay.h>
 #include <linux/smp.h>
 
+#include <asm/dec21285.h>
 #include <asm/hardware.h>
 
 #include "soundmodule.h"
 #include "sound_config.h"
 #include "waveartist.h"
 
+#ifndef _ISA_DMA
+#define _ISA_DMA(x) (x)
+#endif
+#ifndef _ISA_IRQ
+#define _ISA_IRQ(x) (x)
+#endif
+
 #define        VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec
 
 #define        MIXER_PRIVATE3_RESET    0x53570000
@@ -141,8 +149,269 @@ typedef struct wavnc_port_info {
 
 static int              nr_waveartist_devs;
 static wavnc_info       adev_info[MAX_AUDIO_DEV];
+
+static int waveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level);
+
+/*
+ * Corel Netwinder specifics...
+ */
 static struct timer_list vnc_timer;
+extern spinlock_t gpio_lock;
+
+static void
+vnc_mute(wavnc_info *devc, int mute)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+       cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE);
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       devc->mute_state = mute;
+}
+
+static int
+vnc_volume_slider(wavnc_info *devc)
+{
+       static signed int old_slider_volume;
+       unsigned long flags;
+       signed int volume = 255;
+
+       *CSR_TIMER1_LOAD = 0x00ffffff;
+
+       save_flags(flags);
+       cli();
+
+       outb(0xFF, 0x201);
+       *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
+
+       while (volume && (inb(0x201) & 0x01))
+               volume--;
+
+       *CSR_TIMER1_CNTL = 0;
+
+       restore_flags(flags);
+       
+       volume = 0x00ffffff - *CSR_TIMER1_VALUE;
+
+
+#ifndef REVERSE
+       volume = 150 - (volume >> 5);
+#else
+       volume = (volume >> 6) - 25;
+#endif
+
+       if (volume < 0)
+               volume = 0;
+
+       if (volume > 100)
+               volume = 100;
+
+       /*
+        * slider quite often reads +-8, so debounce this random noise
+        */
+       if ((volume - old_slider_volume) > 7 ||
+           (old_slider_volume - volume) > 7) {
+               old_slider_volume = volume;
+
+               DEB(printk("Slider volume: %d.\n", old_slider_volume));
+       }
+
+       return old_slider_volume;
+}
+
+static int
+vnc_slider(wavnc_info *devc)
+{
+       signed int slider_volume;
+       unsigned int temp;
+
+       /*
+        * read the "buttons" state.
+        *  Bit 4 = handset present,
+        *  Bit 5 = offhook
+        */
+       // the state should be "querable" via a private IOCTL call
+       temp = inb(0x201) & 0x30;
+
+       if (!devc->handset_mute_sw &&
+           (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) {
+               devc->handset_state = temp;
+               devc->handset_mute_sw = 0;
+
+               vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0);
+       }
+
+       slider_volume = vnc_volume_slider(devc);
+
+       /*
+        * If we're using software controlled volume, and
+        * the slider moves by more than 20%, then we
+        * switch back to slider controlled volume.
+        */
+       if (devc->slider_vol > slider_volume) {
+               if (devc->slider_vol - slider_volume > 20)
+                       devc->use_slider = 1;
+       } else {
+               if (slider_volume - devc->slider_vol > 20)
+                       devc->use_slider = 1;
+       }
+
+       /*
+        * use only left channel
+        */
+       temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
+
+       if (slider_volume != temp && devc->use_slider) {
+               devc->slider_vol = slider_volume;
+
+               waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
+                       slider_volume | slider_volume << 8);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static void
+vnc_slider_tick(unsigned long data)
+{
+       int next_timeout;
+
+       if (vnc_slider(adev_info + data))
+               next_timeout = 5;       // mixer reported change
+       else
+               next_timeout = VNC_TIMER_PERIOD;
+
+       mod_timer(&vnc_timer, jiffies + next_timeout);
+}
+
+static int
+vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+       wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+       int val, temp;
+
+       if (cmd == SOUND_MIXER_PRIVATE1) {
+               /*
+                * Use this call to override the automatic handset
+                * behaviour - ignore handset.
+                *  bit 7 = total control over handset - do not
+                *          to plug/unplug
+                *  bit 4 = internal mic
+                *  bit 0 = mute internal speaker
+                */
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               devc->handset_mute_sw = val;
+
+               temp = val & VNC_INTERNAL_SPKR;
+               if (devc->mute_state != temp)
+                       vnc_mute(devc, temp);
+
+               devc->handset_state = val & VNC_INTERNAL_MIC;
+               waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
+               return 0;
+       }
+#if 0
+       if (cmd == SOUND_MIXER_PRIVATE2) {
+#define VNC_SOUND_PAUSE         0x53    //to pause the DSP
+#define VNC_SOUND_RESUME        0x57    //to unpause the DSP
+               int             val;
+
+               val = *(int *) arg;
+
+               printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val);
 
+               if (val == VNC_SOUND_PAUSE) {
+                       wa_sendcmd(0x16);    //PAUSE the ADC
+               } else if (val == VNC_SOUND_RESUME) {
+                       wa_sendcmd(0x18);    //RESUME the ADC
+               } else {
+                       return -EINVAL;      //invalid parameters...
+               }
+               return 0;
+       }
+
+       if (cmd == SOUND_MIXER_PRIVATE3) {
+               long unsigned   flags;
+               int             mixer_reg[15];  //reg 14 is actually a command: read,write,reset
+
+               int             val;
+               int             i;
+
+               val = *(int *) arg;
+
+               if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT))
+                       return (-EFAULT);
+
+               memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg));
+
+               if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) {  //reset command??
+                       wavnc_mixer_reset(devc);
+                       return (0);
+               } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) {   //write command??
+//                     printk("WaveArtist Mixer: Private write command.\n");
+
+                       wa_sendcmd(0x32);       //Pair1 - word 1 and 5
+                       wa_sendcmd(mixer_reg[0]);
+                       wa_sendcmd(mixer_reg[4]);
+
+                       wa_sendcmd(0x32);       //Pair2 - word 2 and 6
+                       wa_sendcmd(mixer_reg[1]);
+                       wa_sendcmd(mixer_reg[5]);
+
+                       wa_sendcmd(0x32);       //Pair3 - word 3 and 7
+                       wa_sendcmd(mixer_reg[2]);
+                       wa_sendcmd(mixer_reg[6]);
+
+                       wa_sendcmd(0x32);       //Pair4 - word 4 and 8
+                       wa_sendcmd(mixer_reg[3]);
+                       wa_sendcmd(mixer_reg[7]);
+
+                       wa_sendcmd(0x32);       //Pair5 - word 9 and 10
+                       wa_sendcmd(mixer_reg[8]);
+                       wa_sendcmd(mixer_reg[9]);
+
+                       wa_sendcmd(0x0031);             //set left and right PCM
+                       wa_sendcmd(mixer_reg[0x0A]);
+                       wa_sendcmd(mixer_reg[0x0B]);
+
+                       wa_sendcmd(0x0131);             //set left and right FM
+                       wa_sendcmd(mixer_reg[0x0C]);
+                       wa_sendcmd(mixer_reg[0x0D]);
+
+                       return 0;
+               } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) {    //read command?
+//                     printk("WaveArtist Mixer: Private read command.\n");
+
+                       //first read all current values...
+                       save_flags(flags);
+                       cli();
+
+                       for (i = 0; i < 14; i++) {
+                               wa_sendcmd((i << 8) + 0x30);    // get ready for command nn30H
+
+                               while (!(inb(STATR) & CMD_RF)) {
+                               };      //wait for response ready...
+
+                               mixer_reg[i] = inw(CMDR);
+                       }
+                       restore_flags(flags);
+
+                       if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT))
+                               return (-EFAULT);
+
+                       memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg));
+                       return 0;
+               } else
+                       return -EINVAL;
+       }
+#endif
+       return -EINVAL;
+}
 
 static inline void
 waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set)
@@ -1368,138 +1637,12 @@ static int
 waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
        wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
-#if 0
-       //use this call to override the automatic handset behaviour - ignore handset
-       //bit 0x80 = total control over handset - do not react to plug/unplug
-       //bit 0x10 = 1 == internal mic, otherwise handset mic
-       //bit 0x01 = 1 == mute internal speaker, otherwise unmute
-
-       if (cmd == SOUND_MIXER_PRIVATE1) {
-               int             val, temp;
-
-               val = *(int *) arg;
-
-//             printk("MIXER_PRIVATE1: passed parameter = 0x%X.\n",val);
-               return -EINVAL;         //check if parameter is logical...
-
-               devc->soft_mute_flag = val;
-
-               temp = val & VNC_INTERNAL_SPKR;
-               if (temp != devc->mute_state) {
-//                     printk("MIXER_PRIVATE1: mute_mono(0x%X).\n",temp);
-                       vnc_mute(devc, temp);
-               }
-
-//             temp = devc->handset_state;
-
-               // do not check if it is not already in
-               // the right setting, since we are
-               // laying about the current state...
-
-//             if ((val & VNC_INTERNAL_MIC) != temp) {
-                       devc->handset_state = val & VNC_INTERNAL_MIC;
-//                     printk("MIXER_PRIVATE1: mixer_set(0x%X).\n",devc->handset_state);
-                       wa_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
-//                     devc->handset_state = temp;
-               }
-               return 0;
-       }
-#if 0
-       if (cmd == SOUND_MIXER_PRIVATE2) {
-#define VNC_SOUND_PAUSE         0x53    //to pause the DSP
-#define VNC_SOUND_RESUME        0x57    //to unpause the DSP
-               int             val;
-
-               val = *(int *) arg;
-
-               printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val);
-
-               if (val == VNC_SOUND_PAUSE) {
-                       wa_sendcmd(0x16);    //PAUSE the ADC
-               } else if (val == VNC_SOUND_RESUME) {
-                       wa_sendcmd(0x18);    //RESUME the ADC
-               } else {
-                       return -EINVAL;      //invalid parameters...
-               }
-               return 0;
-       }
-#endif
 
-       if (cmd == SOUND_MIXER_PRIVATE3) {
-               long unsigned   flags;
-               int             mixer_reg[15];  //reg 14 is actually a command: read,write,reset
-
-               int             val;
-               int             i;
-
-               val = *(int *) arg;
-
-               if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT))
-                       return (-EFAULT);
-
-               memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg));
-
-               if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) {  //reset command??
-                       wavnc_mixer_reset(devc);
-                       return (0);
-               } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) {   //write command??
-//                     printk("WaveArtist Mixer: Private write command.\n");
-
-                       wa_sendcmd(0x32);       //Pair1 - word 1 and 5
-                       wa_sendcmd(mixer_reg[0]);
-                       wa_sendcmd(mixer_reg[4]);
+       if (cmd == SOUND_MIXER_PRIVATE1 ||
+           cmd == SOUND_MIXER_PRIVATE2 ||
+           cmd == SOUND_MIXER_PRIVATE3)
+               return vnc_private_ioctl(dev, cmd, arg);
 
-                       wa_sendcmd(0x32);       //Pair2 - word 2 and 6
-                       wa_sendcmd(mixer_reg[1]);
-                       wa_sendcmd(mixer_reg[5]);
-
-                       wa_sendcmd(0x32);       //Pair3 - word 3 and 7
-                       wa_sendcmd(mixer_reg[2]);
-                       wa_sendcmd(mixer_reg[6]);
-
-                       wa_sendcmd(0x32);       //Pair4 - word 4 and 8
-                       wa_sendcmd(mixer_reg[3]);
-                       wa_sendcmd(mixer_reg[7]);
-
-                       wa_sendcmd(0x32);       //Pair5 - word 9 and 10
-                       wa_sendcmd(mixer_reg[8]);
-                       wa_sendcmd(mixer_reg[9]);
-
-                       wa_sendcmd(0x0031);             //set left and right PCM
-                       wa_sendcmd(mixer_reg[0x0A]);
-                       wa_sendcmd(mixer_reg[0x0B]);
-
-                       wa_sendcmd(0x0131);             //set left and right FM
-                       wa_sendcmd(mixer_reg[0x0C]);
-                       wa_sendcmd(mixer_reg[0x0D]);
-
-                       return 0;
-               } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) {    //read command?
-//                     printk("WaveArtist Mixer: Private read command.\n");
-
-                       //first read all current values...
-                       save_flags(flags);
-                       cli();
-
-                       for (i = 0; i < 14; i++) {
-                               wa_sendcmd((i << 8) + 0x30);    // get ready for command nn30H
-
-                               while (!(inb(STATR) & CMD_RF)) {
-                               };      //wait for response ready...
-
-                               mixer_reg[i] = inw(CMDR);
-                       }
-                       restore_flags(flags);
-
-                       if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT))
-                               return (-EFAULT);
-
-                       memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg));
-                       return 0;
-               } else
-                       return -EINVAL;
-       }
-#endif
        if (((cmd >> 8) & 0xff) == 'M') {
                if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
                        int val;
@@ -1660,139 +1803,6 @@ nomem:
        return -1;
 }
 
-/*
- * Corel Netwinder specifics...
- */
-static void
-vnc_mute(wavnc_info *devc, int mute)
-{
-       extern spinlock_t gpio_lock;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-       cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE);
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       devc->mute_state = mute;
-}
-
-static int
-vnc_volume_slider(wavnc_info *devc)
-{
-       static signed int old_slider_volume;
-       unsigned long flags;
-       signed int volume = 255;
-
-       *CSR_TIMER1_LOAD = 0x00ffffff;
-
-       save_flags(flags);
-       cli();
-
-       outb(0xFF, 0x201);
-       *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
-
-       while (volume && (inb(0x201) & 0x01))
-               volume--;
-
-       *CSR_TIMER1_CNTL = 0;
-
-       restore_flags(flags);
-       
-       volume = 0x00ffffff - *CSR_TIMER1_VALUE;
-
-
-#ifndef REVERSE
-       volume = 150 - (volume >> 5);
-#else
-       volume = (volume >> 6) - 25;
-#endif
-
-       if (volume < 0)
-               volume = 0;
-
-       if (volume > 100)
-               volume = 100;
-
-       /*
-        * slider quite often reads +-8, so debounce this random noise
-        */
-       if ((volume - old_slider_volume) > 7 ||
-           (old_slider_volume - volume) > 7) {
-               old_slider_volume = volume;
-
-               DEB(printk("Slider volume: %d.\n", old_slider_volume));
-       }
-
-       return old_slider_volume;
-}
-
-static int
-vnc_slider(wavnc_info *devc)
-{
-       signed int slider_volume;
-       unsigned int temp;
-
-       /*
-        * read the "buttons" state.
-        *  Bit 4 = handset present,
-        *  Bit 5 = offhook
-        */
-       // the state should be "querable" via a private IOCTL call
-       temp = inb(0x201) & 0x30;
-
-       if (!devc->handset_mute_sw &&
-           (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) {
-               devc->handset_state = temp;
-               devc->handset_mute_sw = 0;
-
-               vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0);
-       }
-
-       slider_volume = vnc_volume_slider(devc);
-
-       /*
-        * If we're using software controlled volume, and
-        * the slider moves by more than 20%, then we
-        * switch back to slider controlled volume.
-        */
-       if (devc->slider_vol > slider_volume) {
-               if (devc->slider_vol - slider_volume > 20)
-                       devc->use_slider = 1;
-       } else {
-               if (slider_volume - devc->slider_vol > 20)
-                       devc->use_slider = 1;
-       }
-
-       /*
-        * use only left channel
-        */
-       temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
-
-       if (slider_volume != temp && devc->use_slider) {
-               devc->slider_vol = slider_volume;
-
-               waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
-                       slider_volume | slider_volume << 8);
-
-               return 1;
-       }
-
-       return 0;
-}
-
-static void
-vnc_slider_tick(unsigned long data)
-{
-       int next_timeout;
-
-       if (vnc_slider(adev_info + data))
-               next_timeout = 5;       // mixer reported change
-       else
-               next_timeout = VNC_TIMER_PERIOD;
-
-       mod_timer(&vnc_timer, jiffies + next_timeout);
-}
-
 int
 probe_waveartist(struct address_info *hw_config)
 {
@@ -1808,12 +1818,12 @@ probe_waveartist(struct address_info *hw_config)
                return 0;
        }
 
-       if (hw_config->irq > 31 || hw_config->irq < 16) {
+       if (hw_config->irq > _ISA_IRQ(15) || hw_config->irq < _ISA_IRQ(0)) {
                printk("WaveArtist: Bad IRQ %d\n", hw_config->irq);
                return 0;
        }
 
-       if (hw_config->dma != 3) {
+       if (hw_config->dma != _ISA_DMA(3)) {
                printk("WaveArtist: Bad DMA %d\n", hw_config->dma);
                return 0;
        }
index 360bc95f17d745c05920de8b22b1e39c61ac85d3..45b62d1b55f19964df56c23908ae2caabb382e42 100644 (file)
@@ -2,16 +2,11 @@
 // def file for Rockwell RWA010 chip set, as installed in Corel NetWinder
 
 //registers
-#define        WA_BASE 0
-//x250
-
-#define CMDR   WA_BASE+0
-#define DATR   WA_BASE+2
-
-#define CTLR   WA_BASE+4
-#define        STATR   WA_BASE+5
-
-#define        IRQSTAT WA_BASE+12
+#define CMDR   0
+#define DATR   2
+#define CTLR   4
+#define        STATR   5
+#define        IRQSTAT 12
 
 //bit defs
 //reg STATR
index e1bc0857caf872682189ea1b88a23d645b15a165..42485a999dae81c56ce3b96c9a260be2577e3bc9 100644 (file)
@@ -254,7 +254,9 @@ acornfb_set_timing(struct fb_var_screeninfo *var)
 
        bandwidth = var->pixclock * 8 / var->bits_per_pixel;
        /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
-       if (bandwidth > 71750)
+       if (bandwidth > 143500)
+               vidc_ctl |= VIDC_CTRL_FIFO_3_7;
+       else if (bandwidth > 71750)
                vidc_ctl |= VIDC_CTRL_FIFO_2_6;
        else if (bandwidth > 35875)
                vidc_ctl |= VIDC_CTRL_FIFO_1_5;
index c24288124951e48b4fd3f7adf1468f5a09bd7a72..d342304a31945d05a33a11f680b471c1283d333d 100644 (file)
@@ -121,7 +121,7 @@ static const struct res cyber2000_res[] = {
                1600, 1200,
                {
                        0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
-                       0x00, 0x40,
+                       0x00, 0x40,
                        0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
                },
                0x1f,
@@ -154,54 +154,54 @@ static void cyber2000_init_hw(const struct res *res)
        debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
 
        cyber2000_outb(0xef, 0x3c2);
-       cyber2000_crtcw(0x0b, 0x11);
-       cyber2000_attrw(0x00, 0x11);
+       cyber2000_crtcw(0x11, 0x0b);
+       cyber2000_attrw(0x11, 0x00);
 
-       cyber2000_seqw(0x01, 0x00);
+       cyber2000_seqw(0x00, 0x01);
        cyber2000_seqw(0x01, 0x01);
-       cyber2000_seqw(0x0f, 0x02);
-       cyber2000_seqw(0x00, 0x03);
-       cyber2000_seqw(0x0e, 0x04);
+       cyber2000_seqw(0x02, 0x0f);
        cyber2000_seqw(0x03, 0x00);
+       cyber2000_seqw(0x04, 0x0e);
+       cyber2000_seqw(0x00, 0x03);
 
        for (i = 0; i < sizeof(crtc_idx); i++)
-               cyber2000_crtcw(res->crtc_regs[i], crtc_idx[i]);
+               cyber2000_crtcw(crtc_idx[i], res->crtc_regs[i]);
 
        for (i = 0x0a; i < 0x10; i++)
-               cyber2000_crtcw(0, i);
+               cyber2000_crtcw(i, 0);
 
-       cyber2000_crtcw(0xff, 0x18);
+       cyber2000_crtcw(0x18, 0xff);
 
        cyber2000_grphw(0x00, 0x00);
-       cyber2000_grphw(0x00, 0x01);
-       cyber2000_grphw(0x00, 0x02);
-       cyber2000_grphw(0x00, 0x03);
-       cyber2000_grphw(0x00, 0x04);
-       cyber2000_grphw(0x60, 0x05);
-       cyber2000_grphw(0x05, 0x06);
-       cyber2000_grphw(0x0f, 0x07);
-       cyber2000_grphw(0xff, 0x08);
+       cyber2000_grphw(0x01, 0x00);
+       cyber2000_grphw(0x02, 0x00);
+       cyber2000_grphw(0x03, 0x00);
+       cyber2000_grphw(0x04, 0x00);
+       cyber2000_grphw(0x05, 0x60);
+       cyber2000_grphw(0x06, 0x05);
+       cyber2000_grphw(0x07, 0x0f);
+       cyber2000_grphw(0x08, 0xff);
 
        for (i = 0; i < 16; i++)
                cyber2000_attrw(i, i);
 
-       cyber2000_attrw(0x01, 0x10);
-       cyber2000_attrw(0x00, 0x11);
-       cyber2000_attrw(0x0f, 0x12);
-       cyber2000_attrw(0x00, 0x13);
-       cyber2000_attrw(0x00, 0x14);
+       cyber2000_attrw(0x10, 0x01);
+       cyber2000_attrw(0x11, 0x00);
+       cyber2000_attrw(0x12, 0x0f);
+       cyber2000_attrw(0x13, 0x00);
+       cyber2000_attrw(0x14, 0x00);
 
        for (i = 0; i < sizeof(igs_regs); i += 2)
-               cyber2000_grphw(igs_regs[i+1], igs_regs[i]);
+               cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
 
-       cyber2000_grphw(res->crtc_ofl, 0x11);
+       cyber2000_grphw(0x11, res->crtc_ofl);
 
        for (i = 0; i < 4; i += 1)
-               cyber2000_grphw(res->clk_regs[i], 0xb0 + i);
+               cyber2000_grphw(0xb0 + i, res->clk_regs[i]);
 
-       cyber2000_grphw(0x01, 0x90);
-       cyber2000_grphw(0x80, 0xb9);
-       cyber2000_grphw(0x00, 0xb9);
+       cyber2000_grphw(0x90, 0x01);
+       cyber2000_grphw(0xb9, 0x80);
+       cyber2000_grphw(0xb9, 0x00);
 
        cyber2000_outb(0x56, 0x3ce);
        i = cyber2000_inb(0x3cf);
@@ -311,6 +311,7 @@ cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
        cyber2000_outw(height, 0xbf062);
 
        switch (p->var.bits_per_pixel) {
+       case 15:
        case 16:
                bgx = ((u16 *)p->dispsw_data)[bgx];
        case 8:
@@ -415,14 +416,27 @@ cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        current_par.palette[regno].blue  = blue;
 
        switch (fb_display[current_par.currcon].var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
        case 8:
                cyber2000_outb(regno, 0x3c8);
                cyber2000_outb(red,   0x3c9);
                cyber2000_outb(green, 0x3c9);
                cyber2000_outb(blue,  0x3c9);
                break;
+#endif
 
 #ifdef FBCON_HAS_CFB16
+       case 15:
+               if (regno < 32) {
+                       cyber2000_outb(regno << 3, 0x3c8);
+                       cyber2000_outb(red, 0x3c9);
+                       cyber2000_outb(green, 0x3c9);
+                       cyber2000_outb(blue, 0x3c9);
+               }
+               if (regno < 16)
+                       current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 10;
+               break;
+
        case 16:
                if (regno < 64) {
                        /* write green */
@@ -464,36 +478,123 @@ cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        return 0;
 }
 
-static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+static void cyber2000fb_calculate_timing(unsigned char *v, struct fb_var_screeninfo *var)
 {
-       int width = var->xres_virtual;
-       int scr_pitch, fetchrow;
-       int i;
-       char b, col;
+       int Htotal, Hdispend, Hblankstart, Hblankend, Hsyncstart, Hsyncend;
+       int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+       Hdispend    = var->xres;
+       Hsyncstart  = var->xres + var->right_margin;
+       Hsyncend    = var->xres + var->right_margin + var->hsync_len;
+       Htotal      = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+
+       Hblankstart = var->xres;
+       Hblankend   = Htotal - 4*8;
+
+       Vdispend    = var->yres;
+       Vsyncstart  = var->yres + var->lower_margin;
+       Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
+       Vtotal      = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+       Vblankstart = var->yres + 7;
+       Vblankend   = Vtotal - 11;
+
+       Hdispend    >>= 3;
+       Hsyncstart  >>= 3;
+       Hsyncend    >>= 3;
+       Htotal      >>= 3;
+       Hblankstart >>= 3;
+       Hblankend   >>= 3;
+
+       Htotal      -= 5;
+       Hdispend    -= 1;
+       Vtotal      -= 2;
+       Vdispend    -= 1;
+       Vblankstart -= 1;
+       Vblankend   -= 1;
+
+       v[0]  = Htotal;
+       v[1]  = Hdispend;
+       v[2]  = Hblankstart;
+       v[3]  = BIT(Hblankend,  0, 0x1f,  0) |
+               BIT(1,          0, 0x01,  7);
+       v[4]  = Hsyncstart;
+       v[5]  = BIT(Hsyncend,   0, 0x1f,  0) |
+               BIT(Hblankend,  5, 0x01,  7);
+
+       v[6]  = Vtotal;
+       v[7]  = BIT(Vtotal,     8, 0x01,  0) |
+               BIT(Vdispend,   8, 0x01,  1) |
+               BIT(Vsyncstart, 8, 0x01,  2) |
+               BIT(Vblankstart,8, 0x01,  3) |
+               BIT(1,          0, 0x01,  4) |
+               BIT(Vtotal,     9, 0x01,  5) |
+               BIT(Vdispend,   9, 0x01,  6) |
+               BIT(Vsyncstart, 9, 0x01,  7);
+       v[8]  = 0;
+       v[9]  = BIT(0,          0, 0x1f,  0) |
+               BIT(Vblankstart,9, 0x01,  5) |
+               BIT(1,          0, 0x01,  6);
+       v[10] = Vsyncstart;
+       v[11] = BIT(Vsyncend,   0, 0x0f,  0) |
+               BIT(1,          0, 0x01,  7);
+       v[12] = Vdispend;
+       v[14] = 0;
+       v[15] = Vblankstart;
+       v[16] = Vblankend;
+       v[17] = 0xe3;
+
+       /* overflow - graphics reg 0x11 */
+       v[18] = BIT(Vtotal,     10, 0x01,  0) | /* guess */
+               BIT(Vdispend,   10, 0x01,  1) |
+               BIT(Vsyncstart, 10, 0x01,  2) | /* guess */
+               BIT(Vblankstart,10, 0x01,  3) | /* guess */
+               BIT(Hblankend,   6, 0x01,  4);  /* guess */
+}
+
+static void cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+{
+       unsigned int width = var->xres_virtual;
+       unsigned int scr_pitch, fetchrow, i;
+       char b, graph_r77, crtc[32];
 
        switch (var->bits_per_pixel) {
        case 8: /* PSEUDOCOLOUR, 256 */
                b = 0;
-               col = 1;
-               scr_pitch = var->xres_virtual / 8;
+               graph_r77 = 1;
+               scr_pitch = width;
+               break;
+
+       case 15:/* DIRECTCOLOUR, 32k */
+               b = 1;
+               graph_r77 = 6;
+               scr_pitch = width * 2;
                break;
 
        case 16:/* DIRECTCOLOUR, 64k */
                b = 1;
-               col = 2;
-               scr_pitch = var->xres_virtual / 8 * 2;
+               graph_r77 = 2;
+               scr_pitch = width * 2;
                break;
+
        case 24:/* TRUECOLOUR, 16m */
                b = 2;
-               col = 4;
-               scr_pitch = var->xres_virtual / 8 * 3;
+               graph_r77 = 4;
                width *= 3;
+               scr_pitch = width;
                break;
 
        default:
-               return 1;
+               return;
        }
 
+       width -= 1;
+       scr_pitch >>= 3;
+       fetchrow = scr_pitch + 1;
+
+       cyber2000fb_calculate_timing(crtc, var);
+
        for (i = 0; i < NUM_TOTAL_MODES; i++)
                if (var->xres == cyber2000_res[i].xres &&
                    var->yres == cyber2000_res[i].yres)
@@ -502,30 +603,41 @@ static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
        if (i < NUM_TOTAL_MODES)
                cyber2000_init_hw(cyber2000_res + i);
 
-       fetchrow = scr_pitch + 1;
+       crtc[13] = scr_pitch;
 
-       debug_printf("Setting regs: pitch=%X, fetchrow=%X, col=%X, b=%X\n",
-                    scr_pitch, fetchrow, col, b);
+       /*
+        * reprogram the CRTC with the values we calculated
+        * above.  This should be cleaned up once we're
+        * confident that we're generating the correct
+        * values.  Disable this if you're having problems,
+        * and report the values obtained from the kernel
+        * messages.
+        */
+#if 1
+       cyber2000_crtcw(0x11, 0x0b);
+       for (i = 0; i < sizeof(crtc_idx); i++)
+               cyber2000_crtcw(crtc_idx[i], crtc[i]);
+#else
+       cyber2000_crtcw(0x13, crtc[13]);
+#endif
 
-       cyber2000_outb(0x13, 0x3d4);
-       cyber2000_outb(scr_pitch, 0x3d5);
-       cyber2000_outb(0x14, 0x3ce);
-       cyber2000_outb(fetchrow, 0x3cf);
-       cyber2000_outb(0x15, 0x3ce);
+       cyber2000_grphw(0x14, fetchrow);
                                        /* FIXME: is this the right way round? */
-       cyber2000_outb(((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f), 0x3cf);
-       cyber2000_outb(0x77, 0x3ce);
-       cyber2000_outb(col, 0x3cf);
-
-
-       cyber2000_outb(0x33, 0x3ce);
-       cyber2000_outb(0x1c, 0x3cf);
-
-       cyber2000_outw(width - 1, 0xbf018);
-       cyber2000_outw(width - 1, 0xbf218);
-       cyber2000_outb(b, 0xbf01c);
-
-       return 0;
+       cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f));
+       cyber2000_grphw(0x77, graph_r77);
+       cyber2000_grphw(0x33, 0x1c);
+
+       cyber2000_outw(width, 0xbf018);
+       cyber2000_outw(width, 0xbf218);
+       cyber2000_outb(b,     0xbf01c);
+
+{ int j;
+ printk(KERN_DEBUG);
+ for (j = 0; j < 19; j++) printk("%2d ", j); printk("\n"KERN_DEBUG);
+ for (j = 0; j < 19; j++) printk("%02X ", crtc[j]); printk("\n"KERN_DEBUG);
+ for (j = 0; j < 18; j++) printk("%02X ", cyber2000_res[i].crtc_regs[j]);
+ printk("%02X\n", cyber2000_res[i].crtc_ofl);
+}
 }
 
 static inline void
@@ -536,13 +648,10 @@ cyber2000fb_update_start(struct fb_var_screeninfo *var)
 
        base = var->yoffset * var->xres_virtual + var->xoffset;
 
-       cyber2000_outb(0x0c, 0x3d4);
-       cyber2000_outb(base, 0x3d5);
-       cyber2000_outb(0x0d, 0x3d4);
-       cyber2000_outb(base >> 8, 0x3d5);
+       cyber2000_crtcw(0x0c, base);
+       cyber2000_crtcw(0x0d, base >> 8);
        /* FIXME: need the upper bits of the start offset */
-/*     cyber2000_outb(0x??, 0x3d4);
-       cyber2000_outb(base >> 16, 0x3d5);*/
+/*     cyber2000_crtcw(0x??, base >> 16);*/
 #endif
 }
 
@@ -622,6 +731,7 @@ cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
                break;
 #endif
 #ifdef FBCON_HAS_CFB16
+       case 15:
        case 16:
                *visual = FB_VISUAL_DIRECTCOLOR;
                break;
@@ -737,6 +847,10 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
        }
 
        display->var = *var;
+       display->var.activate &= ~FB_ACTIVATE_ALL;
+
+       if (var->activate & FB_ACTIVATE_ALL)
+               global_disp.var = display->var;
 
        display->screen_base    = (char *)current_par.screen_base;
        display->visual         = visual;
@@ -744,8 +858,6 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
        display->type_aux       = 0;
        display->ypanstep       = 0;
        display->ywrapstep      = 0;
-       display->line_length    =
-       display->next_line      = (var->xres_virtual * var->bits_per_pixel) / 8;
        display->can_soft_blank = 1;
        display->inverse        = 0;
 
@@ -754,18 +866,22 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
        case 8:
                dispsw = &fbcon_cfb8;
                display->dispsw_data = NULL;
+               display->next_line = var->xres_virtual;
                break;
 #endif
 #ifdef FBCON_HAS_CFB16
+       case 15:
        case 16:
                dispsw = &fbcon_cfb16;
                display->dispsw_data = current_par.c_table.cfb16;
+               display->next_line = var->xres_virtual * 2;
                break;
 #endif
 #ifdef FBCON_HAS_CFB24
        case 24:
                dispsw = &fbcon_cfb24;
                display->dispsw_data = current_par.c_table.cfb24;
+               display->next_line = var->xres_virtual * 3;
                break;
 #endif
        default:
@@ -775,6 +891,8 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
                break;
        }
 
+       display->line_length = display->next_line;
+
        if (display->var.accel_flags & FB_ACCELF_TEXT &&
            dispsw != &fbcon_dummy)
                display->dispsw = &fbcon_cyber_accel;
@@ -818,6 +936,7 @@ static int cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
                return -EINVAL;
        if (y_bottom > fb_display[con].var.yres_virtual)
                return -EINVAL;
+/*disabled until we can update the start address properly */
 return -EINVAL;
 
        cyber2000fb_update_start(var);
@@ -947,12 +1066,26 @@ cyber2000fb_init_fbinfo(void))
        init_var.yres                   = DEFAULT_YRES;
        init_var.bits_per_pixel         = DEFAULT_BPP;
 
+       /*
+        * These parameters give
+        * 640x480, hsync 31.5kHz, vsync 60Hz
+        */
+       init_var.left_margin            = 56;
+       init_var.right_margin           = 16;
+       init_var.upper_margin           = 34;
+       init_var.lower_margin           = 9;
+       init_var.hsync_len              = 88;
+       init_var.vsync_len              = 2;
+       init_var.pixclock               = 39722;
+
        init_var.red.msb_right          = 0;
        init_var.green.msb_right        = 0;
        init_var.blue.msb_right         = 0;
 
        switch(init_var.bits_per_pixel) {
-       case 8:
+       default:
+               init_var.bits_per_pixel = 8;
+       case 8: /* PSEUDOCOLOUR */
                init_var.bits_per_pixel = 8;
                init_var.red.offset     = 0;
                init_var.red.length     = 8;
@@ -962,7 +1095,17 @@ cyber2000fb_init_fbinfo(void))
                init_var.blue.length    = 8;
                break;
 
-       case 16:
+       case 15: /* RGB555 */
+               init_var.bits_per_pixel = 15;
+               init_var.red.offset     = 10;
+               init_var.red.length     = 5;
+               init_var.green.offset   = 5;
+               init_var.green.length   = 5;
+               init_var.blue.offset    = 0;
+               init_var.blue.length    = 5;
+               break;
+
+       case 16: /* RGB565 */
                init_var.bits_per_pixel = 16;
                init_var.red.offset     = 11;
                init_var.red.length     = 5;
@@ -972,7 +1115,7 @@ cyber2000fb_init_fbinfo(void))
                init_var.blue.length    = 5;
                break;
 
-       case 24:
+       case 24: /* RGB888 */
                init_var.bits_per_pixel = 24;
                init_var.red.offset     = 16;
                init_var.red.length     = 8;
index f1e81dfa0b8ceb3e9cc3f9c13cb903516fc41607..bbbd1edbb9e0edabcdcd7f17cdecc04b4a38ce50 100644 (file)
 #define cyber2000_inw(reg)     (*(unsigned short *)&CyberRegs[reg])
 #define cyber2000_inl(reg)     (*(unsigned long *)&CyberRegs[reg])
 
-static inline void cyber2000_crtcw(int val, int reg)
+static inline void cyber2000_crtcw(int reg, int val)
 {
        cyber2000_outb(reg, 0x3d4);
        cyber2000_outb(val, 0x3d5);
 }
 
-static inline void cyber2000_grphw(int val, int reg)
+static inline void cyber2000_grphw(int reg, int val)
 {
        cyber2000_outb(reg, 0x3ce);
        cyber2000_outb(val, 0x3cf);
 }
 
-static inline void cyber2000_attrw(int val, int reg)
+static inline void cyber2000_attrw(int reg, int val)
 {
        cyber2000_inb(0x3da);
        cyber2000_outb(reg, 0x3c0);
@@ -33,7 +33,7 @@ static inline void cyber2000_attrw(int val, int reg)
        cyber2000_outb(val, 0x3c0);
 }
 
-static inline void cyber2000_seqw(int val, int reg)
+static inline void cyber2000_seqw(int reg, int val)
 {
        cyber2000_outb(reg, 0x3c4);
        cyber2000_outb(val, 0x3c5);
index 827b9c652e40fb33eb8583c5adc8f21fbee6ba78..b6474f45183d3b495003d09d05556ff79b815198 100644 (file)
@@ -1753,13 +1753,6 @@ int try_to_free_buffers(struct page * page)
                tmp = tmp->b_this_page;
                if (!buffer_busy(p))
                        continue;
-{
-       static int count = 30;
-       if (count) {
-               count--;
-               printk("bh %p (%04x:%ld): count=%d, state=0x%04x\n", p, p->b_dev, p->b_blocknr, p->b_count, p->b_state);
-       }
-}
 
                wakeup_bdflush(0);
                return 0;
index 8b268dd41792af8b38cdf0aabd0dafd2be78aee6..ba9cc7a785438b9918b9dfbe2e9ddba0df6f555f 100644 (file)
@@ -336,7 +336,7 @@ int invalidate_inodes(struct super_block * sb)
  *      dispose_list.
  */
 #define CAN_UNUSE(inode) \
-       (((inode)->i_count | (inode)->i_state) == 0)
+       (((inode)->i_count | (inode)->i_state | (inode)->i_nrpages) == 0)
 #define INODE(entry)   (list_entry(entry, struct inode, i_list))
 
 static int free_inodes(void)
index c64a0222967230c0035f029064451e074eb9e8bb..6f600dd5d7eb9d470d0348db614f45876e64cee2 100644 (file)
@@ -335,7 +335,7 @@ static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int
 
        hash = page_hash(inode, offset);
 repeat:
-       page = __find_lock_page(inode, offset, *hash);
+       page = __find_lock_page(inode, offset, hash);
        if (page) {
                page_cache_free(page_cache);
                goto unlock_out;
@@ -433,7 +433,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                goto no_dirent_page;
 
        hash = page_hash(inode, offset);
-       page = __find_get_page(inode, offset, *hash);
+       page = __find_get_page(inode, offset, hash);
        if (!page)
                goto no_dirent_page;
        if (!Page_Uptodate(page))
index 7d8cdbf74fbb5d9bcce1139846b28a95c7461f39..b2ac2f6f8d0e02939b027b8e45560911e1675aef 100644 (file)
@@ -66,7 +66,7 @@ static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode
 
        hash = page_hash(inode, 0);
 repeat:
-       page = __find_lock_page(inode, 0, *hash);
+       page = __find_lock_page(inode, 0, hash);
        if (page) {
                page_cache_free(page_cache);
                goto unlock_out;
index 9996d444bb0ae04e2c15935d5b9d600a79df3e99..5cf5189597d05a77f776eb66f3f1d66ac223ff42 100644 (file)
@@ -918,13 +918,6 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
        int retval;
        struct vfsmount *vfsmnt;
        
-       /*
-        * Invalidate the inodes, as some mount options may be changed.
-        * N.B. If we are changing media, we should check the return
-        * from invalidate_inodes ... can't allow _any_ open files.
-        */
-       invalidate_inodes(sb);
-
        if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
                return -EACCES;
                /*flags |= MS_RDONLY;*/
@@ -941,6 +934,14 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
        vfsmnt = lookup_vfsmnt(sb->s_dev);
        if (vfsmnt)
                vfsmnt->mnt_flags = sb->s_flags;
+
+       /*
+        * Invalidate the inodes, as some mount options may be changed.
+        * N.B. If we are changing media, we should check the return
+        * from invalidate_inodes ... can't allow _any_ open files.
+        */
+       invalidate_inodes(sb);
+
        return 0;
 }
 
index 031225380f39f77f9112d18a146fc2f1ba29acb2..5729b956d18ee598ccf9d1f25fbada5eb93171aa 100644 (file)
@@ -19,7 +19,8 @@
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
+static __inline__ void
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
index d86a6f98a93d04c6c33f0beeb42f838401950999..1a09f182779ed4e3ab47f2d03a7e4a4f353a4527 100644 (file)
@@ -12,7 +12,8 @@
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
+static __inline__ void
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
@@ -22,7 +23,7 @@ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctr
                reg += 1;
        }
        hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-       hw->irq = *irq;
+       hw->irq = irq;
 }
 
 /*
index ca1a55cdb4ae65dd654e485c27f19a23a9540766..d8f0ab21d8a0629a2ffd67b41478141bc2c30ab1 100644 (file)
@@ -10,7 +10,6 @@
  *  26-Jan-1999        PJB     Don't use IACK on CATS
  *  16-Mar-1999        RMK     Added autodetect of ISA PICs
  */
-#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
index a03cea6396725d8321cfac5a7cd47af64c1f6da6..745750e3be21ebc41cc477d3ab548707a4ed3e7d 100644 (file)
@@ -15,8 +15,6 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
-#include <linux/config.h>
-
 #if defined(CONFIG_HOST_FOOTBRIDGE)
 
 /*
index a8f94c19803e05a41a2c08f61aec4cc2f3939bd2..4f3850b4403f360a9b666e3bdaf246471a419d8f 100644 (file)
@@ -20,16 +20,7 @@ extern __inline__ void arch_reset(char mode)
                 mcr    p15, 0, ip, c7, c7      @ flush caches
                 mov    pc, lr" : : : "cc");
        } else {
-               if (machine_is_ebsa285() || machine_is_co285()) {
-                       /* To reboot, we set up the 21285 watchdog and
-                        * enable it.  We then wait for it to timeout.
-                        */
-                       *CSR_TIMER4_LOAD = 0x8000;
-                       *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE |
-                                          TIMER_CNTL_AUTORELOAD |
-                                          TIMER_CNTL_DIV16;
-                       *CSR_SA110_CNTL |= 1 << 13;
-               } else if (machine_is_netwinder()) {
+               if (machine_is_netwinder()) {
                        /* open up the SuperIO chip
                         */
                        outb(0x87, 0x370);
@@ -48,6 +39,15 @@ extern __inline__ void arch_reset(char mode)
                        /* set a RED LED and toggle WD_TIMER for rebooting
                         */
                        outb(0xc4, 0x338);
+               } else {
+                       /* To reboot, we set up the 21285 watchdog and
+                        * enable it.  We then wait for it to timeout.
+                        */
+                       *CSR_TIMER4_LOAD = 0x8000;
+                       *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE |
+                                          TIMER_CNTL_AUTORELOAD |
+                                          TIMER_CNTL_DIV16;
+                       *CSR_SA110_CNTL |= 1 << 13;
                }
        }
 }
index ed70ecf25247312d4db5181807e5c9a3ec20dd5f..7c5cd89c454fdd1525edf3c7559869863a36dd28 100644 (file)
@@ -333,7 +333,7 @@ extern __inline__ void setup_timer(void)
                set_rtc_mmss = set_dummy_time;
        }
 
-       if (machine_is_ebsa285()) {
+       if (machine_is_ebsa285() || machine_is_co285()) {
                gettimeoffset = timer1_gettimeoffset;
 
                *CSR_TIMER1_CLR  = 0;
index 9826f15f59341a5d451faac93bf550deedb284ca..ccbc7cf76aa6f3f9895536595c328aad4f050634 100644 (file)
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
+static __inline__ void
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
 
+       memset(hw, 0, sizeof(*hw));
+
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
                hw->io_ports[i] = reg;
                reg += 1;
        }
        hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-       hw->irq = *irq;
+       hw->irq = irq;
 }
 
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
  */
-static __inline__ void ide_init_default_hwifs(void)
+static __inline__ void
+ide_init_default_hwifs(void)
 {
        hw_regs_t hw;
 
-        memset(hw, 0, sizeof(*hw));
-
-       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
-       hw.irq = IRQ_HARDDISK;
+       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
        ide_register_hw(&hw, NULL);
 }
index 9f08dae30376773fd23ddf19e9cbc74d42b70f35..01e20e285ba7befcc3774a355ccbff941d4b6fef 100644 (file)
@@ -4,17 +4,19 @@
 static inline unsigned long get_sp(void)
 {
        unsigned long sp;
-       __asm__ ("mov %0,sp" : "=r" (sp));
+       __asm__ ("mov   %0,sp" : "=r" (sp));
        return sp;
 }
 
+//static inline struct task_struct *get_current(void) __attribute__ (( __const__ ));
+
 static inline struct task_struct *get_current(void)
 {
        struct task_struct *ts;
-       __asm__ __volatile__("
-       bic     %0, sp, #0x1f00
-       bic     %0, %0, #0x00ff
-       : "=r" (ts));
+       __asm__ __volatile__ (
+       "bic    %0, sp, #0x1f00         @ get_current
+       bic     %0, %0, #0x00ff
+       : "=r" (ts));
        return ts;
 }
 
index 46d7cab0589d0d3dc844787017f452427d8fdec4..bc7d03ddd12a6fb0c86e8e15e897ab2ac3c2b304 100644 (file)
@@ -119,6 +119,10 @@ extern void set_dma_count(dmach_t channel, unsigned long count);
  */
 extern void set_dma_mode(dmach_t channel, dmamode_t mode);
 
+/* Set the transfer speed for this channel
+ */
+extern void set_dma_speed(dmach_t channel, int cycle_ns);
+
 /* Get DMA residue count. After a DMA transfer, this
  * should return zero. Reading this while a DMA transfer is
  * still in progress will return unpredictable results.
index 6bd9d3c02045b2d004409dd71054bcd5f2b9f088..5b898dfee540b2d3133a457243e5c33a5ea01271 100644 (file)
@@ -46,6 +46,13 @@ typedef union {
 #define ide_release_lock(lock)         do {} while (0)
 #define ide_get_lock(lock, hdlr, data) do {} while (0)
 
+/*
+ * We always use the new IDE port registering,
+ * so these are fixed here.
+ */
+#define ide_default_io_base(i)         ((ide_ioreg_t)0)
+#define ide_default_irq(b)             (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMARM_IDE_H */
index cfa021bcdf682ca9421c74591307006f15d539a5..35db8e667f056eb5247f096b20d32f97e783cc2d 100644 (file)
@@ -189,21 +189,10 @@ __IO(l,"",long)
 #define inl_p(port) __inl_p((port))
 #endif
 
-/* Nothing to do */
-
-#ifndef dma_cache_inv
-#define dma_cache_inv(_start,_size)            do { } while (0)
-#endif
-#ifndef dma_cache_wback
-#define dma_cache_wback(_start,_size)          do { } while (0)
-#ifndef ARCH_READWRITE
-#ifndef dma_cache_wback_inv
-#define dma_cache_wback_inv(_start,_size)      do { } while (0)
 #endif
 
-#endif /* __KERNEL__ */
+#ifndef ARCH_READWRITE
 
-#endif /* __ASM_ARM_IO_H */
 /* for panic */
 #include <linux/kernel.h>
 
index 9bdd7e00e6ed8e61cd262e6311fcd2ecdb8d0ffd..ce59302433ce595fc99f6c621fd32872666cf883 100644 (file)
@@ -24,8 +24,5 @@
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
-#define __STR(x) #x
-#define STR(x) __STR(x)
-
 #endif
 
index f53aa229d65421f75b28b28d407ec6b520e7ac6e..513501b7d2b749d668c9a765722145fe6e9b743f 100644 (file)
@@ -44,6 +44,8 @@ struct pt_regs {
 #define CC_Z_BIT       (1 << 30)
 #define CC_N_BIT       (1 << 31)
 
+#ifdef __KERNEL__
+
 #define processor_mode(regs) \
        ((regs)->ARM_pc & MODE_MASK)
 
@@ -70,11 +72,19 @@ struct pt_regs {
  */
 static inline int valid_user_regs(struct pt_regs *regs)
 {
-       if (!user_mode(regs) || regs->ARM_pc & (F_BIT | I_BIT))
+       if (user_mode(regs) &&
+           (regs->ARM_pc & (F_BIT | I_BIT)) == 0)
                return 1;
 
+       /*
+        * force it to be something sensible
+        */
+       regs->ARM_pc &= ~(MODE_MASK | F_BIT | I_BIT);
+
        return 0;
 }
 
+#endif /* __KERNEL__ */
+
 #endif
 
index 9cd99cf50dc09e360033411158bf7de26fe382d8..19fa29bf9ea96e5b2f8decc161cd75272b6dbd1e 100644 (file)
@@ -14,13 +14,13 @@ extern inline void down(struct semaphore * sem)
        @ atomic down operation
        mov     r0, pc
        orr     lr, r0, #0x08000000
-       and     r0, r0, #0x0c000003
        teqp    lr, #0
        ldr     lr, [%0]
+       and     r0, r0, #0x0c000003
        subs    lr, lr, #1
        str     lr, [%0]
-       mov     lr, pc, lsr #28
-       teqp    r0, lr, lsl #28
+       orrmi   r0, r0, #0x80000000     @ set N
+       teqp    r0, #0
        movmi   r0, %0
        blmi    " SYMBOL_NAME_STR(__down_failed)
                :
@@ -39,14 +39,13 @@ extern inline int down_interruptible (struct semaphore * sem)
        @ atomic down operation
        mov     r0, pc
        orr     lr, r0, #0x08000000
-       and     r0, r0, #0x0c000003
        teqp    lr, #0
        ldr     lr, [%1]
+       and     r0, r0, #0x0c000003
        subs    lr, lr, #1
        str     lr, [%1]
-       mov     lr, pc, lsr #28
        orrmi   r0, r0, #0x80000000     @ set N
-       teqp    r0, lr, lsl #28
+       teqp    r0, #0
        movmi   r0, %1
        movpl   r0, #0
        blmi    " SYMBOL_NAME_STR(__down_interruptible_failed) "
@@ -64,14 +63,13 @@ extern inline int down_trylock(struct semaphore * sem)
        @ atomic down operation
        mov     r0, pc
        orr     lr, r0, #0x08000000
-       and     r0, r0, #0x0c000003
        teqp    lr, #0
        ldr     lr, [%1]
+       and     r0, r0, #0x0c000003
        subs    lr, lr, #1
        str     lr, [%1]
-       mov     lr, pc, lsr #28
        orrmi   r0, r0, #0x80000000     @ set N
-       teqp    r0, lr, lsl #28
+       teqp    r0, #0
        movmi   r0, %1
        movpl   r0, #0
        blmi    " SYMBOL_NAME_STR(__down_trylock_failed) "
@@ -94,14 +92,13 @@ extern inline void up(struct semaphore * sem)
        @ atomic up operation
        mov     r0, pc
        orr     lr, r0, #0x08000000
-       and     r0, r0, #0x0c000003
        teqp    lr, #0
        ldr     lr, [%0]
+       and     r0, r0, #0x0c000003
        adds    lr, lr, #1
        str     lr, [%0]
-       mov     lr, pc, lsr #28
-       orrls   r0, r0, #0x80000000     @ set N
-       teqp    r0, lr, lsl #28
+       orrle   r0, r0, #0x80000000     @ set N
+       teqp    r0, #0
        movmi   r0, %0
        blmi    " SYMBOL_NAME_STR(__up_wakeup)
                :
index 471daf65430a0f2bf9d43d0b94c02080d5264f43..733a6cdff8d9600e4e32a0ff1b95f1366ab27873 100644 (file)
@@ -110,6 +110,12 @@ extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int
          : "memory");                                  \
        } while (0)
 
+/* For spinlocks etc */
+#define local_irq_save(x)      __save_flags_cli(x)
+#define local_irq_restore(x)   __restore_flags(x)
+#define local_irq_disable()    __cli()
+#define local_irq_enable()     __sti()
+
 #ifdef __SMP__
 #error SMP not supported
 #else
index b24305bd420031d101da128e37cd1d52bbe19028..01f0a8ac8a664ce824c3e526802249ed2a7a7452 100644 (file)
@@ -52,6 +52,8 @@ struct pt_regs {
 #define CC_Z_BIT       (1 << 30)
 #define CC_N_BIT       (1 << 31)
 
+#ifdef __KERNEL__
+
 #if 0 /* GCC/egcs should be able to optimise this, IMHO */
 #define user_mode(regs)        \
        ((((regs)->ARM_cpsr & MODE_MASK) == USR_MODE) || \
@@ -81,8 +83,8 @@ struct pt_regs {
  */
 static inline int valid_user_regs(struct pt_regs *regs)
 {
-       if ((regs->ARM_cpsr & 0xf) == 0 ||
-           (regs->ARM_cpsr & (F_BIT|I_BIT)))
+       if ((regs->ARM_cpsr & 0xf) == 0 &&
+           (regs->ARM_cpsr & (F_BIT|I_BIT)) == 0)
                return 1;
 
        /*
@@ -93,5 +95,7 @@ static inline int valid_user_regs(struct pt_regs *regs)
        return 0;
 }
 
+#endif /* __KERNEL__ */
+
 #endif
 
index 52098bc5c07c587b85b90deefd9569a64ed57ecd..45ceaa3f1099328dd7abab17e8dfa9c05d3ab58c 100644 (file)
@@ -16,12 +16,12 @@ extern inline void down(struct semaphore * sem)
        @ atomic down operation
        mrs     %0, cpsr
        orr     %1, %0, #128            @ disable IRQs
-       bic     %0, %0, #0x80000000     @ clear N
        msr     cpsr, %1
        ldr     %1, [%2]
+       bic     %0, %0, #0x80000000     @ clear N
        subs    %1, %1, #1
-       orrmi   %0, %0, #0x80000000     @ set N
        str     %1, [%2]
+       orrmi   %0, %0, #0x80000000     @ set N
        msr     cpsr, %0
        movmi   r0, %2
        blmi    " SYMBOL_NAME_STR(__down_failed)
@@ -42,12 +42,12 @@ extern inline int down_interruptible (struct semaphore * sem)
        @ atomic down interruptible operation
        mrs     %0, cpsr
        orr     %1, %0, #128            @ disable IRQs
-       bic     %0, %0, #0x80000000     @ clear N
        msr     cpsr, %1
        ldr     %1, [%2]
+       bic     %0, %0, #0x80000000     @ clear N
        subs    %1, %1, #1
-       orrmi   %0, %0, #0x80000000     @ set N
        str     %1, [%2]
+       orrmi   %0, %0, #0x80000000     @ set N
        msr     cpsr, %0
        movmi   r0, %2
        movpl   r0, #0
@@ -68,12 +68,12 @@ extern inline int down_trylock(struct semaphore *sem)
        @ atomic down try lock operation
        mrs     %0, cpsr
        orr     %1, %0, #128            @ disable IRQs
-       bic     %0, %0, #0x80000000     @ clear N
        msr     cpsr, %1
        ldr     %1, [%2]
+       bic     %0, %0, #0x80000000     @ clear N
        subs    %1, %1, #1
-       orrmi   %0, %0, #0x80000000     @ set N
        str     %1, [%2]
+       orrmi   %0, %0, #0x80000000     @ set N
        msr     cpsr, %0
        movmi   r0, %2
        movpl   r0, #0
@@ -100,12 +100,12 @@ extern inline void up(struct semaphore * sem)
        @ atomic up operation
        mrs     %0, cpsr
        orr     %1, %0, #128            @ disable IRQs
-       bic     %0, %0, #0x80000000     @ clear N
        msr     cpsr, %1
        ldr     %1, [%2]
+       bic     %0, %0, #0x80000000     @ clear N
        adds    %1, %1, #1
-       orrls   %0, %0, #0x80000000     @ set N
        str     %1, [%2]
+       orrle   %0, %0, #0x80000000     @ set N
        msr     cpsr, %0
        movmi   r0, %2
        blmi    " SYMBOL_NAME_STR(__up_wakeup)
index 9de0fccc5ea8a6896655be56d1c9ecbb430aa4f0..2aa59a26e656a5416830195d81008af9a89bf484 100644 (file)
@@ -121,6 +121,12 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */
          : "memory");                  \
        } while (0)
 
+/* For spinlocks etc */
+#define local_irq_save(x)      __save_flags_cli(x)
+#define local_irq_restore(x)   __restore_flags(x)
+#define local_irq_disable()    __cli()
+#define local_irq_enable()     __sti()
+
 #ifdef __SMP__
 #error SMP not supported
 #else
index f308d67b1c39a7bfec06239760b3f6d36639dfe4..97141aa25f103b3e0197b36248fc9fb9467aba68 100644 (file)
@@ -36,6 +36,7 @@ typedef unsigned long mm_segment_t;           /* domain register      */
 
 #define NR_DEBUGS      5
 
+#include <asm/proc/ptrace.h>
 #include <asm/arch/processor.h>
 #include <asm/proc/processor.h>
 
@@ -86,6 +87,7 @@ extern __inline__ void init_thread_css(struct context_save_struct *save)
 }
 
 /* Forward declaration, a strange C thing */
+struct task_struct;
 struct mm_struct;
 
 /* Free all resources held by a thread. */
index 05456d7dee8100bf740d1fdd06eabc026cf07da8..111e24f962ac8c02f054d4ea4d303c0048f84d60 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/linkage.h>
 #include <asm/atomic.h>
+#include <linux/wait.h>
 
 struct semaphore {
        atomic_t count;
@@ -13,8 +14,35 @@ struct semaphore {
        wait_queue_head_t wait;
 };
 
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL })
+#define __SEMAPHORE_INIT(name,count)                   \
+       { ATOMIC_INIT(count), 0,                        \
+         __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
+
+#define __MUTEX_INITIALIZER(name) \
+       __SEMAPHORE_INIT(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count)        \
+       struct semaphore name = __SEMAPHORE_INIT(name,count)
+
+#define DECLARE_MUTEX(name)            __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name)     __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+#define sema_init(sem, val)                    \
+do {                                           \
+       atomic_set(&((sem)->count), (val));     \
+       (sem)->waking = 0;                      \
+       init_waitqueue_head(&(sem)->wait);      \
+} while (0)
+
+static inline void init_MUTEX(struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED(struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
 
 asmlinkage void __down_failed (void /* special register calling convention */);
 asmlinkage int  __down_interruptible_failed (void /* special register calling convention */);
@@ -26,7 +54,7 @@ extern int  __down_interruptible(struct semaphore * sem);
 extern int  __down_trylock(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-#define sema_init(sem, val)    atomic_set(&((sem)->count), (val))
+extern spinlock_t semaphore_wake_lock;
 
 #include <asm/proc/semaphore.h>
 
index 6bad79dd4a7d452de330572884f3cce395b627dd..28ac2eb2a36746690ad9408cd290808562c02d9c 100644 (file)
@@ -5,10 +5,18 @@
 #include <asm/hardirq.h>
 
 extern unsigned int local_bh_count[NR_CPUS];
-#define in_bh()                        (local_bh_count[smp_processor_id()] != 0)
+
+#define cpu_bh_disable(cpu)    do { local_bh_count[(cpu)]++; barrier(); } while (0)
+#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count[(cpu)]--; } while (0)
+
+#define cpu_bh_trylock(cpu)    (local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
+#define cpu_bh_endlock(cpu)    (local_bh_count[(cpu)] = 0)
+
+#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
+#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
 
 #define get_active_bhs()       (bh_mask & bh_active)
-#define clear_active_bhs(x)    atomic_clear_mask((int)(x),&bh_active)
+#define clear_active_bhs(x)    atomic_clear_mask((x),&bh_active)
 
 extern inline void init_bh(int nr, void (*routine)(void))
 {
@@ -19,8 +27,9 @@ extern inline void init_bh(int nr, void (*routine)(void))
 
 extern inline void remove_bh(int nr)
 {
-       bh_base[nr] = NULL;
        bh_mask &= ~(1 << nr);
+       mb();
+       bh_base[nr] = NULL;
 }
 
 extern inline void mark_bh(int nr)
@@ -34,20 +43,20 @@ extern inline void mark_bh(int nr)
 
 extern inline void start_bh_atomic(void)
 {
-       local_bh_count[smp_processor_id()]++;
+       local_bh_disable();
        barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
        barrier();
-       local_bh_count[smp_processor_id()]--;
+       local_bh_enable();
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)   (in_bh() ? 0 : (local_bh_count[smp_processor_id()]=1))
-#define softirq_endlock(cpu)   (local_bh_count[smp_processor_id()] = 0)
-#define synchronize_bh()       do { } while (0)
+#define softirq_trylock(cpu)   (cpu_bh_trylock(cpu))
+#define softirq_endlock(cpu)   (cpu_bh_endlock(cpu))
+#define synchronize_bh()       barrier()
 
 #endif /* SMP */
 
index 33e1fe183ffc3fdbfd93b042fc33b5dfc3a83a9e..74022ebae27cb2b6f668c1e9f31edfae350b9372 100644 (file)
@@ -1,39 +1,96 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-#ifndef __SMP__
-
 /*
  * To be safe, we assume the only compiler that can cope with
  * empty initialisers is EGCS.
  */
 #if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 90))
-#define EMPTY_INIT_OK
+#define EMPTY_STRUCT           struct { }
+#define EMPTY_STRUCT_INIT(t)   (t) { }
+#else
+#define EMPTY_STRUCT           unsigned char
+#define EMPTY_STRUCT_INIT(t)   (t) 0
 #endif
 
+/*
+ * These are the generic versions of the spinlocks
+ * and read-write locks.. We should actually do a
+ * <linux/spinlock.h> with all of this. Oh, well.
+ */
+#define spin_lock_irqsave(lock, flags)         do { local_irq_save(flags);       spin_lock(lock); } while (0)
+#define spin_lock_irq(lock)                    do { local_irq_disable();         spin_lock(lock); } while (0)
+#define spin_lock_bh(lock)                     do { local_bh_disable();          spin_lock(lock); } while (0)
+
+#define read_lock_irqsave(lock, flags)         do { local_irq_save(flags);       read_lock(lock); } while (0)
+#define read_lock_irq(lock)                    do { local_irq_disable();         read_lock(lock); } while (0)
+#define read_lock_bh(lock)                     do { local_bh_disable();          read_lock(lock); } while (0)
+
+#define write_lock_irqsave(lock, flags)                do { local_irq_save(flags);      write_lock(lock); } while (0)
+#define write_lock_irq(lock)                   do { local_irq_disable();        write_lock(lock); } while (0)
+#define write_lock_bh(lock)                    do { local_bh_disable();         write_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags)    do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
+#define spin_unlock_irq(lock)                  do { spin_unlock(lock);  local_irq_enable();       } while (0)
+#define spin_unlock_bh(lock)                   do { spin_unlock(lock);  local_bh_enable();        } while (0)
+
+#define read_unlock_irqrestore(lock, flags)    do { read_unlock(lock);  local_irq_restore(flags); } while (0)
+#define read_unlock_irq(lock)                  do { read_unlock(lock);  local_irq_enable();       } while (0)
+#define read_unlock_bh(lock)                   do { read_unlock(lock);  local_bh_enable();        } while (0)
+
+#define write_unlock_irqrestore(lock, flags)   do { write_unlock(lock); local_irq_restore(flags); } while (0)
+#define write_unlock_irq(lock)                 do { write_unlock(lock); local_irq_enable();       } while (0)
+#define write_unlock_bh(lock)                  do { write_unlock(lock); local_bh_enable();        } while (0)
+
+#ifndef __SMP__
+
+#define DEBUG_SPINLOCKS 0      /* 0 == no debugging, 1 == maintain lock state, 2 == full debugging */
+
+#if (DEBUG_SPINLOCKS < 1)
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  */
-#ifdef EMPTY_INIT_OK
-  typedef struct { } spinlock_t;
-# define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef unsigned char spinlock_t;
-# define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef EMPTY_STRUCT spinlock_t;
+#define SPIN_LOCK_UNLOCKED EMPTY_STRUCT_INIT(spinlock_t)
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
-#define spin_trylock(lock)     do { } while(0)
+#define spin_trylock(lock)     (1)
 #define spin_unlock_wait(lock) do { } while(0)
 #define spin_unlock(lock)      do { } while(0)
-#define spin_lock_irq(lock)    cli()
-#define spin_unlock_irq(lock)  sti()
 
-#define spin_lock_irqsave(lock, flags) \
-       do { __save_flags_cli(flags); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
+#elif (DEBUG_SPINLOCKS < 2)
+
+typedef struct {
+       volatile unsigned int lock;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED (pinlock_t) { 0 }
+
+#define spin_lock_init(x)      do { (x)->lock = 0; } while (0)
+#define spin_lock(x)           do { (x)->lock = 1; } while (0)
+#define spin_trylock(lock)     (!test_and_set_bit(0,(lock)))
+#define spin_unlock_wait(x)    do { } while (0)
+#define spin_unlock(x)         do { (x)->lock = 0; } while (0)
+
+#else /* (DEBUG_SPINLOCKS >= 2) */
+
+typedef struct {
+       volatule unsigned int lock;
+       volatile unsigned int babble;
+       const char *module;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
+
+#include <linux/kernel.h>
+
+#define spin_lock_init(x)      do { (x)->lock = 0; } while (0)
+#define spin_trylock(lock)     (!test_and_set_bit(0,(lock)))
+
+#define spin_lock(x)           do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
+#define spin_unlock_wait(x)    do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
+#define spin_unlock(x)         do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
+
+#endif
 
 /*
  * Read-write spinlocks, allowing multiple readers
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-#ifdef EMPTY_INIT_OK
-  typedef struct { } rwlock_t;
-# define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef unsigned char rwlock_t;
-# define RW_LOCK_UNLOCKED 0
-#endif
+typedef EMPTY_STRUCT rwlock_t;
+#define RW_LOCK_UNLOCKED EMPTY_STRUCT_INIT(rwlock_t)
 
 #define read_lock(lock)                do { } while(0)
 #define read_unlock(lock)      do { } while(0)
 #define write_lock(lock)       do { } while(0)
 #define write_unlock(lock)     do { } while(0)
-#define read_lock_irq(lock)    cli()
-#define read_unlock_irq(lock)  sti()
-#define write_lock_irq(lock)   cli()
-#define write_unlock_irq(lock) sti()
-
-#define read_lock_irqsave(lock, flags) \
-       do { __save_flags_cli(flags); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
-#define write_lock_irqsave(lock, flags)        \
-       do { __save_flags_cli(flags); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
 
 #else
 #error ARM architecture does not support spin locks
index 2874c4661f49e851514624238c29a10253a6a202..80252899dcfa9926c250dd614dc2361572c647d7 100644 (file)
@@ -35,7 +35,7 @@ extern unsigned int __machine_arch_type;
 
 /*
  * Sort out a definition for machine_arch_type
- * The rules basically are:
+ * The rules are:
  * 1. If one architecture is selected, then all machine_is_xxx()
  *    are constant.
  * 2. If two or more architectures are selected, then the selected
@@ -118,28 +118,16 @@ extern unsigned int __machine_arch_type;
 #define machine_arch_type      __machine_arch_type
 #endif
 
-/*
- * task_struct isn't always declared - forward-declare it here.
- */
-struct task_struct;
-
 #include <asm/proc-fns.h>
 
-extern void arm_malalignedptr(const char *, void *, volatile void *);
-extern void arm_invalidptr(const char *, int);
-
 #define xchg(ptr,x) \
        ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 #define tas(ptr) (xchg((ptr),1))
 
-/*
- * switch_to(prev, next) should switch from task `prev' to `next'
- * `prev' will never be the same as `next'.
- *
- * `next' and `prev' should be struct task_struct, but it isn't always defined
- */
-#define switch_to(prev,next,last) do { last = processor._switch_to(prev,next); } while (0)
+extern void arm_malalignedptr(const char *, void *, volatile void *);
+extern void arm_invalidptr(const char *, int);
+extern asmlinkage void __backtrace(void);
 
 /*
  * Include processor dependent parts
@@ -152,7 +140,16 @@ extern void arm_invalidptr(const char *, int);
 #define wmb() mb()
 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
 
-extern asmlinkage void __backtrace(void);
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.
+ * The `mb' is to tell GCC not to cache `current' across this call.
+ */
+#define switch_to(prev,next,last)                      \
+       do {                                            \
+               last = processor._switch_to(prev,next); \
+               mb();                                   \
+       } while (0)
 
 #endif
 
index 86c0c28834fffe60b563eeac859f4b20806474c6..f4a7ed33af05e54c17153b11eac080cee14ca1ce 100644 (file)
@@ -59,7 +59,7 @@
 #define __NR_geteuid                   (__NR_SYSCALL_BASE+ 49)
 #define __NR_getegid                   (__NR_SYSCALL_BASE+ 50)
 #define __NR_acct                      (__NR_SYSCALL_BASE+ 51)
-#define __NR_phys                      (__NR_SYSCALL_BASE+ 52)
+#define __NR_umount2                   (__NR_SYSCALL_BASE+ 52)
 #define __NR_lock                      (__NR_SYSCALL_BASE+ 53)
 #define __NR_ioctl                     (__NR_SYSCALL_BASE+ 54)
 #define __NR_fcntl                     (__NR_SYSCALL_BASE+ 55)
index e03f86c7585938dd56971ff1a7d56689e2de1963..89cd1c3a968eb5fc70cd2a787745faa9f4af0ec7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.13 1999/04/06 06:54:36 jj Exp $
+/* $Id: namei.h,v 1.14 1999/06/10 05:23:12 davem Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
index 57e46e7b02a6ac7fda1823614b25f154306b3103..b014e1739a98d8d2abb07a85c3c0ef95206fcfa7 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
+#define PAGE_BUG(page) do { \
+                               BUG(); } while (0)
+
 #define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
index 57e74b4d3cf24d88b5067323dfab4a5dfc96c420..2cad9d56fee3ee85d0e11fb1b751f021113b441f 100644 (file)
@@ -17,7 +17,7 @@ typedef unsigned char spinlock_t;
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
-#define spin_trylock(lock)     do { } while(0)
+#define spin_trylock(lock)     (1)
 #define spin_unlock_wait(lock) do { } while(0)
 #define spin_unlock(lock)      do { } while(0)
 #define spin_lock_irq(lock)    cli()
index 521bfb72aab21c2d0331566fead79586f5a8fca7..e0db514fce2adf19d6ff995f627615007cbc7446 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.18 1998/09/09 05:36:08 davem Exp $ */
+/* $Id: elf.h,v 1.19 1999/06/11 13:26:04 jj Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -7,7 +7,9 @@
  */
 
 #include <asm/ptrace.h>
+#ifdef __KERNEL__
 #include <asm/processor.h>
+#endif
 
 /*
  * These are used to set parameters in the core dumps.
index 2dbcdedf3bb8939b271a9b622f81701335ae46a1..d3d57545c186702870d497176e683287627cee5a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.14 1999/04/06 06:54:39 jj Exp $
+/* $Id: namei.h,v 1.15 1999/06/10 05:23:17 davem Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
index 0894bb90d09f05109fc56b1a4520b716bbcd166f..1a808c0ba61ee7d298f0f613c22aa84499aec0e6 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
+#define PAGE_BUG(page) do { \
+                               BUG(); } while (0)
+
 extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
 
index d0c25a965966ad43b9331b6eccfc399dd4194754..b3311df9db07a6fb2355c548a3824962ee4fd3b5 100644 (file)
@@ -15,7 +15,7 @@ typedef unsigned char spinlock_t;
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
-#define spin_trylock(lock)     do { } while(0)
+#define spin_trylock(lock)     (1)
 #define spin_unlock_wait(lock) do { } while(0)
 #define spin_unlock(lock)      do { } while(0)
 #define spin_lock_irq(lock)    cli()
index 3974bc23b802a7e28a8f622f20c73ee05c833d22..dcb407c614160b56e61b214852a8d118628d05eb 100644 (file)
@@ -342,6 +342,15 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
diff --git a/include/linux/fd1772.h b/include/linux/fd1772.h
new file mode 100644 (file)
index 0000000..871d6e4
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef _LINUX_FD1772REG_H
+#define _LINUX_FD1772REG_H
+
+/*
+** WD1772 stuff - originally from the M68K Linux
+ * Modified for Archimedes by Dave Gilbert (gilbertd@cs.man.ac.uk)
+ */
+
+/* register codes */
+
+#define FDC1772SELREG_STP   (0x80)   /* command/status register */
+#define FDC1772SELREG_TRA   (0x82)   /* track register */
+#define FDC1772SELREG_SEC   (0x84)   /* sector register */
+#define FDC1772SELREG_DTA   (0x86)   /* data register */
+
+/* register names for FDC1772_READ/WRITE macros */
+
+#define FDC1772REG_CMD         0
+#define FDC1772REG_STATUS      0
+#define FDC1772REG_TRACK       2
+#define FDC1772REG_SECTOR      4
+#define FDC1772REG_DATA                6
+
+/* command opcodes */
+
+#define FDC1772CMD_RESTORE  (0x00)   /*  -                   */
+#define FDC1772CMD_SEEK     (0x10)   /*   |                  */
+#define FDC1772CMD_STEP     (0x20)   /*   |  TYP 1 Commands  */
+#define FDC1772CMD_STIN     (0x40)   /*   |                  */
+#define FDC1772CMD_STOT     (0x60)   /*  -                   */
+#define FDC1772CMD_RDSEC    (0x80)   /*  -   TYP 2 Commands  */
+#define FDC1772CMD_WRSEC    (0xa0)   /*  -          "        */
+#define FDC1772CMD_RDADR    (0xc0)   /*  -                   */
+#define FDC1772CMD_RDTRA    (0xe0)   /*   |  TYP 3 Commands  */
+#define FDC1772CMD_WRTRA    (0xf0)   /*  -                   */
+#define FDC1772CMD_FORCI    (0xd0)   /*  -   TYP 4 Command   */
+
+/* command modifier bits */
+
+#define FDC1772CMDADD_SR6   (0x00)   /* step rate settings */
+#define FDC1772CMDADD_SR12  (0x01)
+#define FDC1772CMDADD_SR2   (0x02)
+#define FDC1772CMDADD_SR3   (0x03)
+#define FDC1772CMDADD_V     (0x04)   /* verify */
+#define FDC1772CMDADD_H     (0x08)   /* wait for spin-up */
+#define FDC1772CMDADD_U     (0x10)   /* update track register */
+#define FDC1772CMDADD_M     (0x10)   /* multiple sector access */
+#define FDC1772CMDADD_E     (0x04)   /* head settling flag */
+#define FDC1772CMDADD_P     (0x02)   /* precompensation */
+#define FDC1772CMDADD_A0    (0x01)   /* DAM flag */
+
+/* status register bits */
+
+#define        FDC1772STAT_MOTORON     (0x80)   /* motor on */
+#define        FDC1772STAT_WPROT       (0x40)   /* write protected (FDC1772CMD_WR*) */
+#define        FDC1772STAT_SPINUP      (0x20)   /* motor speed stable (Type I) */
+#define        FDC1772STAT_DELDAM      (0x20)   /* sector has deleted DAM (Type II+III) */
+#define        FDC1772STAT_RECNF       (0x10)   /* record not found */
+#define        FDC1772STAT_CRC         (0x08)   /* CRC error */
+#define        FDC1772STAT_TR00        (0x04)   /* Track 00 flag (Type I) */
+#define        FDC1772STAT_LOST        (0x04)   /* Lost Data (Type II+III) */
+#define        FDC1772STAT_IDX         (0x02)   /* Index status (Type I) */
+#define        FDC1772STAT_DRQ         (0x02)   /* DRQ status (Type II+III) */
+#define        FDC1772STAT_BUSY        (0x01)   /* FDC1772 is busy */
+
+
+/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1  1 -> Side 2 */
+#define DSKSIDE     (0x01)
+        
+#define DSKDRVNONE  (0x06)
+#define DSKDRV0     (0x02)
+#define DSKDRV1     (0x04)
+
+/* step rates */
+#define        FDC1772STEP_6   0x00
+#define        FDC1772STEP_12  0x01
+#define        FDC1772STEP_2   0x02
+#define        FDC1772STEP_3   0x03
+
+#endif
index 0f7a128e9e4c1a4dfce68af40a5b8bdc2b00e0c5..c5a8af7c7f73bd53f20d0430b920f145362bfc8b 100644 (file)
@@ -65,14 +65,14 @@ static inline unsigned long _page_hashfn(struct inode * inode, unsigned long off
 #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
 
 extern struct page * __find_get_page (struct inode * inode,
-                               unsigned long offset, struct page *page);
+                               unsigned long offset, struct page **hash);
 #define find_get_page(inode, offset) \
-               __find_get_page(inode, offset, *page_hash(inode, offset))
+               __find_get_page(inode, offset, page_hash(inode, offset))
 extern struct page * __find_lock_page (struct inode * inode,
-                               unsigned long offset, struct page *page);
+                               unsigned long offset, struct page **hash);
 extern void lock_page(struct page *page);
 #define find_lock_page(inode, offset) \
-               __find_lock_page(inode, offset, *page_hash(inode, offset))
+               __find_lock_page(inode, offset, page_hash(inode, offset))
 
 extern void __add_page_to_hash_queue(struct page * page, struct page **p);
 
@@ -83,21 +83,6 @@ static inline void add_page_to_hash_queue(struct page * page, struct inode * ino
        __add_page_to_hash_queue(page, page_hash(inode,offset));
 }
 
-static inline void remove_page_from_inode_queue(struct page * page)
-{
-       struct inode * inode = page->inode;
-
-       inode->i_nrpages--;
-       if (inode->i_pages == page)
-               inode->i_pages = page->next;
-       if (page->next)
-               page->next->prev = page->prev;
-       if (page->prev)
-               page->prev->next = page->next;
-       page->next = NULL;
-       page->prev = NULL;
-}
-
 static inline void add_page_to_inode_queue(struct inode * inode, struct page * page)
 {
        struct page **p = &inode->i_pages;
index 45bac06e5883de93ba625ab8d2a02396caf8aa34..19f8871a25a5148c1f75d62d9055194a23ed1e84 100644 (file)
 /*
  * Vendor and card ID's: sort these numerically according to vendor
  * (and according to card ID within vendor). Send all updates to
- * <linux-pcisupport@cck.uni-kl.de>.
+ * <pci-ids@ucw.cz>.
  */
 #define PCI_VENDOR_ID_COMPAQ           0x0e11
 #define PCI_DEVICE_ID_COMPAQ_1280      0x3033
@@ -1254,6 +1254,8 @@ struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struc
 struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 
+#define PCI_ANY_ID (~0)
+
 #define pci_present pcibios_present
 int pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val);
 int pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val);
index dac3a159aeb53c53076ec04f07d646d232fecd42..bd76695dda439aa480040f0bb912f41cc30b84e1 100644 (file)
@@ -80,6 +80,41 @@ static void remove_page_from_hash_queue(struct page * page)
        atomic_dec(&page_cache_size);
 }
 
+static void remove_page_from_inode_queue(struct page * page)
+{
+       struct inode * inode = page->inode;
+       struct page *prev, *next;
+
+       inode->i_nrpages--;
+       next = page->next;
+       prev = page->prev;
+       if (inode->i_pages == page)
+               inode->i_pages = next;
+       if (next)
+               next->prev = prev;
+       if (prev)
+               prev->next = next;
+       page->next = NULL;
+       page->prev = NULL;
+}
+
+/*
+ * Remove a page from the page cache and free it. Caller has to make
+ * sure the page is locked and that nobody else uses it - or that usage
+ * is safe.
+ */
+void remove_inode_page(struct page *page)
+{
+       if (!PageLocked(page))
+               PAGE_BUG(page);
+
+       spin_lock(&pagecache_lock);
+       remove_page_from_inode_queue(page);
+       remove_page_from_hash_queue(page);
+       page->inode = NULL;
+       spin_unlock(&pagecache_lock);
+}
+
 void invalidate_inode_pages(struct inode * inode)
 {
        struct page ** p;
@@ -98,11 +133,8 @@ repeat:
                }
                if (page_count(page) != 2)
                        printk("hm, busy page invalidated? (not necesserily a bug)\n");
-               inode->i_nrpages--;
-               if ((*p = page->next) != NULL)
-                       (*p)->prev = page->prev;
-               page->next = NULL;
-               page->prev = NULL;
+
+               remove_page_from_inode_queue(page);
                remove_page_from_hash_queue(page);
                page->inode = NULL;
                UnlockPage(page);
@@ -131,14 +163,10 @@ repeat:
                /* page wholly truncated - free it */
                if (offset >= start) {
                        get_page(page);
-                       if (TryLockPage(page)) {
-                               spin_unlock(&pagecache_lock);
-                               wait_on_page(page);
-                               page_cache_release(page);
-                               goto repeat;
-                       }
                        spin_unlock(&pagecache_lock);
 
+                       lock_page(page);
+
                        if (inode->i_op->flushpage)
                                inode->i_op->flushpage(inode, page, 0);
 
@@ -150,21 +178,7 @@ repeat:
                         * page cache and creates a buffer-cache alias
                         * to it causing all sorts of fun problems ...
                         */
-                       spin_lock(&pagecache_lock);
-                       inode->i_nrpages--;
-                       if ((*p = page->next) != NULL)
-                               (*p)->prev = page->prev;
-                       page->next = NULL;
-                       page->prev = NULL;
-                       remove_page_from_hash_queue(page);
-                       page->inode = NULL;
-
-                       if (page_count(page) == 1) {
-                               spin_unlock(&pagecache_lock);
-                               PAGE_BUG(page);
-                       }
-
-                       spin_unlock(&pagecache_lock);
+                       remove_inode_page(page);
 
                        UnlockPage(page);
                        page_cache_release(page);
@@ -191,18 +205,9 @@ repeat:
                if (offset < PAGE_CACHE_SIZE) {
                        unsigned long address;
                        get_page(page);
-                       if (TryLockPage(page)) {
-                               spin_unlock(&pagecache_lock);
-                               wait_on_page(page);
-                               page_cache_release(page);
-                               goto repeat;
-                       }
-                       /*
-                        * It's worth dropping the write lock only at
-                        * this point. We are holding the page lock
-                        * so nobody can do anything bad to us.
-                        */
                        spin_unlock(&pagecache_lock);
+
+                       lock_page(page);
                        partial = 1;
 
                        address = page_address(page);
@@ -223,23 +228,6 @@ repeat:
        spin_unlock(&pagecache_lock);
 }
 
-/*
- * Remove a page from the page cache and free it. Caller has to make
- * sure the page is locked and that nobody else uses it - or that usage
- * is safe.
- */
-void remove_inode_page(struct page *page)
-{
-       if (!PageLocked(page))
-               PAGE_BUG(page);
-
-       spin_lock(&pagecache_lock);
-       remove_page_from_inode_queue(page);
-       remove_page_from_hash_queue(page);
-       page->inode = NULL;
-       spin_unlock(&pagecache_lock);
-}
-
 int shrink_mmap(int priority, int gfp_mask)
 {
        static unsigned long clock = 0;
@@ -492,8 +480,9 @@ void lock_page(struct page *page)
  * hashed page atomically, waiting for it if it's locked.
  */
 struct page * __find_get_page (struct inode * inode,
-                               unsigned long offset, struct page *page)
+                               unsigned long offset, struct page **hash)
 {
+       struct page *page;
 
        /*
         * We scan the hash list read-only. Addition to and removal from
@@ -501,7 +490,7 @@ struct page * __find_get_page (struct inode * inode,
         */
 repeat:
        spin_lock(&pagecache_lock);
-       page = __find_page_nolock(inode, offset, page);
+       page = __find_page_nolock(inode, offset, *hash);
        if (page)
                get_page(page);
        spin_unlock(&pagecache_lock);
@@ -540,10 +529,10 @@ repeat:
  * Get the lock to a page atomically.
  */
 struct page * __find_lock_page (struct inode * inode,
-                               unsigned long offset, struct page *page)
+                               unsigned long offset, struct page **hash)
 {
        int locked;
-
+       struct page *page;
 
        /*
         * We scan the hash list read-only. Addition to and removal from
@@ -551,7 +540,7 @@ struct page * __find_lock_page (struct inode * inode,
         */
 repeat:
        spin_lock(&pagecache_lock);
-       page = __find_page_nolock(inode, offset, page);
+       page = __find_page_nolock(inode, offset, *hash);
        locked = 0;
        if (page) {
                get_page(page);
@@ -1216,7 +1205,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
         */
        hash = page_hash(inode, offset);
 retry_find:
-       page = __find_get_page(inode, offset, *hash);
+       page = __find_get_page(inode, offset, hash);
        if (!page)
                goto no_cached_page;
 
@@ -1287,7 +1276,7 @@ no_cached_page:
         * cache.. The page we just got may be useful if we
         * can't share, so don't get rid of it here.
         */
-       page = __find_get_page(inode, offset, *hash);
+       page = __find_get_page(inode, offset, hash);
        if (page)
                goto found_page;
 
@@ -1777,7 +1766,7 @@ generic_file_write(struct file *file, const char *buf,
 
                hash = page_hash(inode, pgpos);
 repeat_find:
-               page = __find_lock_page(inode, pgpos, *hash);
+               page = __find_lock_page(inode, pgpos, hash);
                if (!page) {
                        if (!page_cache) {
                                page_cache = page_cache_alloc();